mirror of
https://github.com/alexpasmantier/television.git
synced 2025-06-06 11:35:25 +00:00
top menus
This commit is contained in:
parent
4bec64e245
commit
9eea37a5b5
@ -4,9 +4,7 @@ down = "SelectNextEntry"
|
||||
up = "SelectPrevEntry"
|
||||
ctrl-n = "SelectNextEntry"
|
||||
ctrl-p = "SelectPrevEntry"
|
||||
alt-down = "ScrollPreviewHalfPageDown"
|
||||
ctrl-d = "ScrollPreviewHalfPageDown"
|
||||
alt-up = "ScrollPreviewHalfPageUp"
|
||||
ctrl-u = "ScrollPreviewHalfPageUp"
|
||||
enter = "SelectEntry"
|
||||
ctrl-enter = "SendToChannel"
|
||||
@ -20,4 +18,3 @@ ctrl-n = "SelectNextEntry"
|
||||
ctrl-p = "SelectPrevEntry"
|
||||
enter = "SelectEntry"
|
||||
ctrl-s = "ToggleChannelSelection"
|
||||
|
||||
|
@ -8,10 +8,10 @@
|
||||
_______________
|
||||
|,----------. |\
|
||||
|| |=| |
|
||||
|| || | |
|
||||
|| . _o| | |
|
||||
|| | | |
|
||||
|| |o| |
|
||||
|`-----------' |/
|
||||
~~~~~~~~~~~~~~~
|
||||
`--------------'
|
||||
__ __ _ _
|
||||
/ /____ / /__ _ __(_)__ (_)__ ___
|
||||
/ __/ -_) / -_) |/ / (_-</ / _ \/ _ \
|
||||
|
@ -14,12 +14,15 @@ use ratatui::{
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{collections::HashMap, str::FromStr};
|
||||
use strum::Display;
|
||||
use tokio::sync::mpsc::UnboundedSender;
|
||||
|
||||
use crate::ui::input::Input;
|
||||
use crate::ui::layout::{Dimensions, Layout};
|
||||
use crate::ui::preview::DEFAULT_PREVIEW_TITLE_FG;
|
||||
use crate::ui::results::build_results_list;
|
||||
use crate::ui::{
|
||||
layout::{Dimensions, Layout},
|
||||
logo::build_logo_paragraph,
|
||||
};
|
||||
use crate::utils::strings::EMPTY_STRING;
|
||||
use crate::{action::Action, config::Config};
|
||||
use crate::{channels::tv_guide::TvGuide, ui::get_border_style};
|
||||
@ -27,13 +30,16 @@ use crate::{channels::OnAir, utils::strings::shrink_with_ellipsis};
|
||||
use crate::{
|
||||
channels::TelevisionChannel, ui::input::actions::InputActionHandler,
|
||||
};
|
||||
use crate::{channels::UnitChannel, ui::input::Input};
|
||||
use crate::{
|
||||
entry::{Entry, ENTRY_PLACEHOLDER},
|
||||
ui::spinner::Spinner,
|
||||
};
|
||||
use crate::{previewers::Previewer, ui::spinner::SpinnerState};
|
||||
|
||||
#[derive(PartialEq, Copy, Clone, Hash, Eq, Debug, Serialize, Deserialize)]
|
||||
#[derive(
|
||||
PartialEq, Copy, Clone, Hash, Eq, Debug, Serialize, Deserialize, Display,
|
||||
)]
|
||||
pub enum Mode {
|
||||
Channel,
|
||||
Guide,
|
||||
@ -98,6 +104,10 @@ impl Television {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn current_channel(&self) -> UnitChannel {
|
||||
UnitChannel::from(&self.channel)
|
||||
}
|
||||
|
||||
/// FIXME: this needs rework
|
||||
pub fn change_channel(&mut self, channel: TelevisionChannel) {
|
||||
self.reset_preview_scroll();
|
||||
@ -304,19 +314,17 @@ impl Television {
|
||||
Action::ScrollPreviewUp => self.scroll_preview_up(1),
|
||||
Action::ScrollPreviewHalfPageDown => self.scroll_preview_down(20),
|
||||
Action::ScrollPreviewHalfPageUp => self.scroll_preview_up(20),
|
||||
Action::ToggleChannelSelection => {
|
||||
match self.mode {
|
||||
Mode::Channel => {
|
||||
self.reset_screen();
|
||||
self.mode = Mode::Guide;
|
||||
}
|
||||
Mode::Guide => {
|
||||
self.reset_screen();
|
||||
self.mode = Mode::Channel;
|
||||
}
|
||||
Mode::SendToChannel => {}
|
||||
Action::ToggleChannelSelection => match self.mode {
|
||||
Mode::Channel => {
|
||||
self.reset_screen();
|
||||
self.mode = Mode::Guide;
|
||||
}
|
||||
}
|
||||
Mode::Guide => {
|
||||
self.reset_screen();
|
||||
self.mode = Mode::Channel;
|
||||
}
|
||||
Mode::SendToChannel => {}
|
||||
},
|
||||
Action::SelectEntry => {
|
||||
if let Some(entry) = self.get_selected_entry() {
|
||||
match self.mode {
|
||||
@ -387,19 +395,38 @@ impl Television {
|
||||
},
|
||||
);
|
||||
|
||||
let help_block = Block::default()
|
||||
.borders(Borders::NONE)
|
||||
let metadata_block = Block::default()
|
||||
.borders(Borders::ALL)
|
||||
.border_type(BorderType::Rounded)
|
||||
.border_style(Style::default().fg(Color::Blue))
|
||||
.padding(Padding::horizontal(1))
|
||||
.style(Style::default());
|
||||
|
||||
let metadata_table = self.build_metadata_table().block(metadata_block);
|
||||
|
||||
f.render_widget(metadata_table, layout.help_bar_left);
|
||||
|
||||
let keymaps_block = Block::default()
|
||||
.borders(Borders::ALL)
|
||||
.border_type(BorderType::Rounded)
|
||||
.border_style(Style::default().fg(Color::Blue))
|
||||
.style(Style::default())
|
||||
.padding(Padding::uniform(1));
|
||||
.padding(Padding::horizontal(1));
|
||||
|
||||
let help_text = self
|
||||
.build_help_paragraph()?
|
||||
.style(Style::default().fg(Color::DarkGray).italic())
|
||||
.alignment(Alignment::Center)
|
||||
.wrap(Wrap { trim: true })
|
||||
.block(help_block);
|
||||
let keymaps_table = self.build_help_table()?.block(keymaps_block);
|
||||
|
||||
f.render_widget(help_text, layout.help_bar);
|
||||
f.render_widget(keymaps_table, layout.help_bar_middle);
|
||||
|
||||
let logo_block = Block::default()
|
||||
.borders(Borders::ALL)
|
||||
.border_type(BorderType::Rounded)
|
||||
.border_style(Style::default().fg(Color::Blue))
|
||||
.style(Style::default().fg(Color::Yellow))
|
||||
.padding(Padding::horizontal(1));
|
||||
|
||||
let logo_paragraph = build_logo_paragraph().block(logo_block);
|
||||
|
||||
f.render_widget(logo_paragraph, layout.help_bar_right);
|
||||
|
||||
self.results_area_height = u32::from(layout.results.height);
|
||||
if let Some(preview_window) = layout.preview_window {
|
||||
@ -489,7 +516,7 @@ impl Television {
|
||||
"> ",
|
||||
Style::default().fg(DEFAULT_INPUT_FG).bold(),
|
||||
))
|
||||
.block(arrow_block);
|
||||
.block(arrow_block);
|
||||
f.render_widget(arrow, inner_input_chunks[0]);
|
||||
|
||||
let interactive_input_block = Block::default();
|
||||
@ -527,8 +554,8 @@ impl Television {
|
||||
),
|
||||
Style::default().fg(DEFAULT_RESULTS_COUNT_FG).italic(),
|
||||
))
|
||||
.block(result_count_block)
|
||||
.alignment(Alignment::Right);
|
||||
.block(result_count_block)
|
||||
.alignment(Alignment::Right);
|
||||
f.render_widget(result_count_paragraph, inner_input_chunks[2]);
|
||||
|
||||
// Make the cursor visible and ask tui-rs to put it at the
|
||||
@ -537,8 +564,8 @@ impl Television {
|
||||
// Put cursor past the end of the input text
|
||||
inner_input_chunks[1].x
|
||||
+ u16::try_from(
|
||||
self.input.visual_cursor().max(scroll) - scroll,
|
||||
)?,
|
||||
self.input.visual_cursor().max(scroll) - scroll,
|
||||
)?,
|
||||
// Move one line down, from the border to the input line
|
||||
inner_input_chunks[1].y,
|
||||
));
|
||||
|
@ -3,6 +3,8 @@ use ratatui::style::{Color, Style, Stylize};
|
||||
pub mod help;
|
||||
pub mod input;
|
||||
pub mod layout;
|
||||
pub mod logo;
|
||||
pub mod metadata;
|
||||
pub mod preview;
|
||||
pub mod results;
|
||||
pub mod spinner;
|
||||
|
@ -1,8 +1,9 @@
|
||||
use color_eyre::eyre::{OptionExt, Result};
|
||||
use ratatui::{
|
||||
layout::Constraint,
|
||||
style::{Color, Style},
|
||||
text::{Line, Span},
|
||||
widgets::Paragraph,
|
||||
widgets::{Cell, Row, Table},
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
|
||||
@ -12,142 +13,118 @@ use crate::{
|
||||
television::{Mode, Television},
|
||||
};
|
||||
|
||||
const SEPARATOR: &str = " ";
|
||||
const ACTION_COLOR: Color = Color::DarkGray;
|
||||
const KEY_COLOR: Color = Color::LightYellow;
|
||||
|
||||
impl Television {
|
||||
pub fn build_help_paragraph<'a>(&self) -> Result<Paragraph<'a>> {
|
||||
pub fn build_help_table<'a>(&self) -> Result<Table<'a>> {
|
||||
match self.mode {
|
||||
Mode::Channel => self.build_help_paragraph_for_channel(),
|
||||
Mode::Guide => self.build_help_paragraph_for_channel_selection(),
|
||||
Mode::SendToChannel => self.build_help_paragraph_for_channel(),
|
||||
Mode::Channel => self.build_help_table_for_channel(),
|
||||
Mode::Guide => self.build_help_table_for_channel_selection(),
|
||||
Mode::SendToChannel => self.build_help_table_for_channel(),
|
||||
}
|
||||
}
|
||||
|
||||
fn build_help_paragraph_for_channel<'a>(&self) -> Result<Paragraph<'a>> {
|
||||
fn build_help_table_for_channel<'a>(&self) -> Result<Table<'a>> {
|
||||
let keymap = self.keymap_for_mode()?;
|
||||
let mut lines = Vec::new();
|
||||
|
||||
// NAVIGATION and SELECTION line
|
||||
let mut ns_line = Line::default();
|
||||
|
||||
// Results navigation
|
||||
let prev = keys_for_action(keymap, Action::SelectPrevEntry);
|
||||
let next = keys_for_action(keymap, Action::SelectNextEntry);
|
||||
let results_spans =
|
||||
build_spans_for_key_groups("↕ Results", vec![prev, next]);
|
||||
|
||||
ns_line.extend(results_spans);
|
||||
ns_line.push_span(Span::styled(SEPARATOR, Style::default()));
|
||||
let prev = keys_for_action(keymap, &Action::SelectPrevEntry);
|
||||
let next = keys_for_action(keymap, &Action::SelectNextEntry);
|
||||
let results_row = Row::new(build_cells_for_key_groups(
|
||||
"↕ Results navigation",
|
||||
vec![prev, next],
|
||||
));
|
||||
|
||||
// Preview navigation
|
||||
let up_keys = keys_for_action(keymap, Action::ScrollPreviewHalfPageUp);
|
||||
let up_keys =
|
||||
keys_for_action(keymap, &Action::ScrollPreviewHalfPageUp);
|
||||
let down_keys =
|
||||
keys_for_action(keymap, Action::ScrollPreviewHalfPageDown);
|
||||
let preview_spans =
|
||||
build_spans_for_key_groups("↕ Preview", vec![up_keys, down_keys]);
|
||||
|
||||
ns_line.extend(preview_spans);
|
||||
ns_line.push_span(Span::styled(SEPARATOR, Style::default()));
|
||||
keys_for_action(keymap, &Action::ScrollPreviewHalfPageDown);
|
||||
let preview_row = Row::new(build_cells_for_key_groups(
|
||||
"↕ Preview navigation",
|
||||
vec![up_keys, down_keys],
|
||||
));
|
||||
|
||||
// Select entry
|
||||
let select_entry_keys = keys_for_action(keymap, Action::SelectEntry);
|
||||
let select_entry_spans = build_spans_for_key_groups(
|
||||
"Select entry",
|
||||
let select_entry_keys = keys_for_action(keymap, &Action::SelectEntry);
|
||||
let select_entry_row = Row::new(build_cells_for_key_groups(
|
||||
"✓ Select entry",
|
||||
vec![select_entry_keys],
|
||||
);
|
||||
|
||||
ns_line.extend(select_entry_spans);
|
||||
ns_line.push_span(Span::styled(SEPARATOR, Style::default()));
|
||||
));
|
||||
|
||||
// Send to channel
|
||||
let send_to_channel_keys =
|
||||
keys_for_action(keymap, Action::SendToChannel);
|
||||
// TODO: add send icon
|
||||
let send_to_channel_spans =
|
||||
build_spans_for_key_groups("Send to", vec![send_to_channel_keys]);
|
||||
|
||||
ns_line.extend(send_to_channel_spans);
|
||||
ns_line.push_span(Span::styled(SEPARATOR, Style::default()));
|
||||
keys_for_action(keymap, &Action::SendToChannel);
|
||||
let send_to_channel_row = Row::new(build_cells_for_key_groups(
|
||||
"⇉ Send results to",
|
||||
vec![send_to_channel_keys],
|
||||
));
|
||||
|
||||
// Switch channels
|
||||
let switch_channels_keys =
|
||||
keys_for_action(keymap, Action::ToggleChannelSelection);
|
||||
let switch_channels_spans = build_spans_for_key_groups(
|
||||
"Switch channels",
|
||||
keys_for_action(keymap, &Action::ToggleChannelSelection);
|
||||
let switch_channels_row = Row::new(build_cells_for_key_groups(
|
||||
"⨀ Switch channels",
|
||||
vec![switch_channels_keys],
|
||||
);
|
||||
|
||||
ns_line.extend(switch_channels_spans);
|
||||
lines.push(ns_line);
|
||||
));
|
||||
|
||||
// MISC line (quit, help, etc.)
|
||||
// let mut misc_line = Line::default();
|
||||
//
|
||||
// // Quit
|
||||
// let quit_keys = keys_for_action(keymap, Action::Quit);
|
||||
// let quit_spans = build_spans_for_key_groups("Quit", vec![quit_keys]);
|
||||
//
|
||||
// misc_line.extend(quit_spans);
|
||||
//
|
||||
// lines.push(misc_line);
|
||||
// Quit ⏼
|
||||
let quit_keys = keys_for_action(keymap, &Action::Quit);
|
||||
let quit_row =
|
||||
Row::new(build_cells_for_key_groups("⏼ Quit", vec![quit_keys]));
|
||||
|
||||
Ok(Paragraph::new(lines))
|
||||
let widths = vec![Constraint::Fill(1), Constraint::Fill(2)];
|
||||
|
||||
Ok(Table::new(
|
||||
vec![
|
||||
results_row,
|
||||
preview_row,
|
||||
select_entry_row,
|
||||
send_to_channel_row,
|
||||
switch_channels_row,
|
||||
quit_row,
|
||||
],
|
||||
widths,
|
||||
))
|
||||
}
|
||||
|
||||
fn build_help_paragraph_for_channel_selection<'a>(
|
||||
&self,
|
||||
) -> Result<Paragraph<'a>> {
|
||||
fn build_help_table_for_channel_selection<'a>(&self) -> Result<Table<'a>> {
|
||||
let keymap = self.keymap_for_mode()?;
|
||||
let mut lines = Vec::new();
|
||||
|
||||
// NAVIGATION + SELECTION line
|
||||
let mut ns_line = Line::default();
|
||||
|
||||
// Results navigation
|
||||
let prev = keys_for_action(keymap, Action::SelectPrevEntry);
|
||||
let next = keys_for_action(keymap, Action::SelectNextEntry);
|
||||
let results_spans =
|
||||
build_spans_for_key_groups("↕ Results", vec![prev, next]);
|
||||
|
||||
ns_line.extend(results_spans);
|
||||
ns_line.push_span(Span::styled(SEPARATOR, Style::default()));
|
||||
let prev = keys_for_action(keymap, &Action::SelectPrevEntry);
|
||||
let next = keys_for_action(keymap, &Action::SelectNextEntry);
|
||||
let results_row = Row::new(build_cells_for_key_groups(
|
||||
"↕ Results",
|
||||
vec![prev, next],
|
||||
));
|
||||
|
||||
// Select entry
|
||||
let select_entry_keys = keys_for_action(keymap, Action::SelectEntry);
|
||||
let select_entry_spans = build_spans_for_key_groups(
|
||||
let select_entry_keys = keys_for_action(keymap, &Action::SelectEntry);
|
||||
let select_entry_row = Row::new(build_cells_for_key_groups(
|
||||
"Select entry",
|
||||
vec![select_entry_keys],
|
||||
);
|
||||
|
||||
ns_line.extend(select_entry_spans);
|
||||
ns_line.push_span(Span::styled(SEPARATOR, Style::default()));
|
||||
));
|
||||
|
||||
// Switch channels
|
||||
let switch_channels_keys =
|
||||
keys_for_action(keymap, Action::ToggleChannelSelection);
|
||||
let switch_channels_spans = build_spans_for_key_groups(
|
||||
keys_for_action(keymap, &Action::ToggleChannelSelection);
|
||||
let switch_channels_row = Row::new(build_cells_for_key_groups(
|
||||
"Switch channels",
|
||||
vec![switch_channels_keys],
|
||||
);
|
||||
|
||||
ns_line.extend(switch_channels_spans);
|
||||
|
||||
lines.push(ns_line);
|
||||
|
||||
// MISC line (quit, help, etc.)
|
||||
// let mut misc_line = Line::default();
|
||||
));
|
||||
|
||||
// Quit
|
||||
// let quit_keys = keys_for_action(keymap, Action::Quit);
|
||||
// let quit_spans = build_spans_for_key_groups("Quit", vec![quit_keys]);
|
||||
let quit_keys = keys_for_action(keymap, &Action::Quit);
|
||||
let quit_row =
|
||||
Row::new(build_cells_for_key_groups("Quit", vec![quit_keys]));
|
||||
|
||||
// misc_line.extend(quit_spans);
|
||||
|
||||
// lines.push(misc_line);
|
||||
|
||||
Ok(Paragraph::new(lines))
|
||||
Ok(Table::new(
|
||||
vec![results_row, select_entry_row, switch_channels_row, quit_row],
|
||||
vec![Constraint::Fill(1), Constraint::Fill(2)],
|
||||
))
|
||||
}
|
||||
|
||||
/// Get the keymap for the current mode.
|
||||
@ -189,21 +166,23 @@ impl Television {
|
||||
///
|
||||
/// assert_eq!(spans.len(), 5);
|
||||
/// ```
|
||||
fn build_spans_for_key_groups(
|
||||
fn build_cells_for_key_groups(
|
||||
group_name: &str,
|
||||
key_groups: Vec<Vec<String>>,
|
||||
) -> Vec<Span> {
|
||||
if key_groups.is_empty() || key_groups.iter().all(|keys| keys.is_empty()) {
|
||||
return vec![];
|
||||
) -> Vec<Cell> {
|
||||
if key_groups.is_empty() || key_groups.iter().all(std::vec::Vec::is_empty)
|
||||
{
|
||||
return vec![group_name.into(), "No keybindings".into()];
|
||||
}
|
||||
let non_empty_groups = key_groups.iter().filter(|keys| !keys.is_empty());
|
||||
let mut spans = vec![
|
||||
Span::styled(
|
||||
group_name.to_owned() + ": ",
|
||||
Style::default().fg(ACTION_COLOR),
|
||||
),
|
||||
Span::styled("[", Style::default().fg(KEY_COLOR)),
|
||||
];
|
||||
let mut cells = vec![Cell::from(Span::styled(
|
||||
group_name.to_owned() + ": ",
|
||||
Style::default().fg(ACTION_COLOR),
|
||||
))];
|
||||
|
||||
let mut spans = Vec::new();
|
||||
//spans.push(Span::styled("[", Style::default().fg(KEY_COLOR)));
|
||||
|
||||
let key_group_spans: Vec<Span> = non_empty_groups
|
||||
.map(|keys| {
|
||||
let key_group = keys.join(", ");
|
||||
@ -213,12 +192,14 @@ fn build_spans_for_key_groups(
|
||||
key_group_spans.iter().enumerate().for_each(|(i, span)| {
|
||||
spans.push(span.clone());
|
||||
if i < key_group_spans.len() - 1 {
|
||||
spans.push(Span::styled(" | ", Style::default().fg(KEY_COLOR)));
|
||||
spans.push(Span::styled(" / ", Style::default().fg(KEY_COLOR)));
|
||||
}
|
||||
});
|
||||
|
||||
spans.push(Span::styled("]", Style::default().fg(KEY_COLOR)));
|
||||
spans
|
||||
//spans.push(Span::styled("]", Style::default().fg(KEY_COLOR)));
|
||||
cells.push(Cell::from(Line::from(spans)));
|
||||
|
||||
cells
|
||||
}
|
||||
|
||||
/// Get the keys for a given action.
|
||||
@ -246,11 +227,11 @@ fn build_spans_for_key_groups(
|
||||
/// ```
|
||||
fn keys_for_action(
|
||||
keymap: &HashMap<Key, Action>,
|
||||
action: Action,
|
||||
action: &Action,
|
||||
) -> Vec<String> {
|
||||
keymap
|
||||
.iter()
|
||||
.filter(|(_key, act)| **act == action)
|
||||
.filter(|(_key, act)| *act == action)
|
||||
.map(|(key, _act)| format!("{key}"))
|
||||
.collect()
|
||||
}
|
||||
|
@ -19,7 +19,9 @@ impl Default for Dimensions {
|
||||
}
|
||||
|
||||
pub struct Layout {
|
||||
pub help_bar: Rect,
|
||||
pub help_bar_left: Rect,
|
||||
pub help_bar_middle: Rect,
|
||||
pub help_bar_right: Rect,
|
||||
pub results: Rect,
|
||||
pub input: Rect,
|
||||
pub preview_title: Option<Rect>,
|
||||
@ -28,14 +30,18 @@ pub struct Layout {
|
||||
|
||||
impl Layout {
|
||||
pub fn new(
|
||||
help_bar: Rect,
|
||||
help_bar_left: Rect,
|
||||
help_bar_middle: Rect,
|
||||
help_bar_right: Rect,
|
||||
results: Rect,
|
||||
input: Rect,
|
||||
preview_title: Option<Rect>,
|
||||
preview_window: Option<Rect>,
|
||||
) -> Self {
|
||||
Self {
|
||||
help_bar,
|
||||
help_bar_left,
|
||||
help_bar_middle,
|
||||
help_bar_right,
|
||||
results,
|
||||
input,
|
||||
preview_title,
|
||||
@ -52,9 +58,19 @@ impl Layout {
|
||||
// split the main block into two vertical chunks (help bar + rest)
|
||||
let hz_chunks = layout::Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints([Constraint::Fill(1), Constraint::Length(5)])
|
||||
.constraints([Constraint::Length(9), Constraint::Fill(1)])
|
||||
.split(main_block);
|
||||
|
||||
// split the help bar into three horizontal chunks (left + center + right)
|
||||
let help_bar_chunks = layout::Layout::default()
|
||||
.direction(Direction::Horizontal)
|
||||
.constraints([
|
||||
Constraint::Fill(1),
|
||||
Constraint::Fill(1),
|
||||
Constraint::Length(24),
|
||||
])
|
||||
.split(hz_chunks[0]);
|
||||
|
||||
if with_preview {
|
||||
// split the main block into two vertical chunks
|
||||
let vt_chunks = layout::Layout::default()
|
||||
@ -63,7 +79,7 @@ impl Layout {
|
||||
Constraint::Percentage(50),
|
||||
Constraint::Percentage(50),
|
||||
])
|
||||
.split(hz_chunks[0]);
|
||||
.split(hz_chunks[1]);
|
||||
|
||||
// left block: results + input field
|
||||
let left_chunks = layout::Layout::default()
|
||||
@ -78,7 +94,9 @@ impl Layout {
|
||||
.split(vt_chunks[1]);
|
||||
|
||||
Self::new(
|
||||
hz_chunks[1],
|
||||
help_bar_chunks[0],
|
||||
help_bar_chunks[1],
|
||||
help_bar_chunks[2],
|
||||
left_chunks[0],
|
||||
left_chunks[1],
|
||||
Some(right_chunks[0]),
|
||||
@ -89,9 +107,17 @@ impl Layout {
|
||||
let chunks = layout::Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints([Constraint::Min(10), Constraint::Length(3)])
|
||||
.split(hz_chunks[0]);
|
||||
.split(hz_chunks[1]);
|
||||
|
||||
Self::new(hz_chunks[1], chunks[0], chunks[1], None, None)
|
||||
Self::new(
|
||||
help_bar_chunks[0],
|
||||
help_bar_chunks[1],
|
||||
help_bar_chunks[2],
|
||||
chunks[0],
|
||||
chunks[1],
|
||||
None,
|
||||
None,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
26
crates/television/ui/logo.rs
Normal file
26
crates/television/ui/logo.rs
Normal file
@ -0,0 +1,26 @@
|
||||
use ratatui::widgets::Paragraph;
|
||||
|
||||
//const LOGO: &str = r" _______________
|
||||
// __ __ _ _ |,----------. |\
|
||||
// / /____ / /__ _ __(_)__ (_)__ ___ || |=| |
|
||||
// / __/ -_) / -_) |/ / (_-</ / _ \/ _ \ || | | |
|
||||
// \__/\__/_/\__/|___/_/___/_/\___/_//_/ || |o| |
|
||||
// |`-----------' |/
|
||||
// `--------------'";
|
||||
|
||||
const LOGO: &str = r" _______________
|
||||
|,----------. |\
|
||||
|| |=| |
|
||||
|| | | |
|
||||
|| |o| |
|
||||
|`-----------' |/
|
||||
`--------------'";
|
||||
|
||||
pub fn build_logo_paragraph<'a>() -> Paragraph<'a> {
|
||||
let lines = LOGO
|
||||
.lines()
|
||||
.map(std::convert::Into::into)
|
||||
.collect::<Vec<_>>();
|
||||
let logo_paragraph = Paragraph::new(lines);
|
||||
logo_paragraph
|
||||
}
|
113
crates/television/ui/metadata.rs
Normal file
113
crates/television/ui/metadata.rs
Normal file
@ -0,0 +1,113 @@
|
||||
use ratatui::{
|
||||
layout::Constraint,
|
||||
style::{Color, Style},
|
||||
text::Span,
|
||||
widgets::{Cell, Row, Table},
|
||||
};
|
||||
|
||||
use crate::television::Television;
|
||||
|
||||
// television 0.1.6
|
||||
// target triple: aarch64-apple-darwin
|
||||
// build: 1.82.0 (2024-10-24)
|
||||
// current_channel: git_repos
|
||||
// current_mode: channel
|
||||
|
||||
impl Television {
|
||||
pub fn build_metadata_table<'a>(&self) -> Table<'a> {
|
||||
let version_row = Row::new(vec![
|
||||
Cell::from(Span::styled(
|
||||
"version: ",
|
||||
Style::default().fg(Color::DarkGray),
|
||||
)),
|
||||
Cell::from(Span::styled(
|
||||
env!("CARGO_PKG_VERSION"),
|
||||
Style::default().fg(Color::LightYellow),
|
||||
)),
|
||||
]);
|
||||
|
||||
let target_triple_row = Row::new(vec![
|
||||
Cell::from(Span::styled(
|
||||
"target triple: ",
|
||||
Style::default().fg(Color::DarkGray),
|
||||
)),
|
||||
Cell::from(Span::styled(
|
||||
env!("VERGEN_CARGO_TARGET_TRIPLE"),
|
||||
Style::default().fg(Color::LightYellow),
|
||||
)),
|
||||
]);
|
||||
|
||||
let build_row = Row::new(vec![
|
||||
Cell::from(Span::styled(
|
||||
"build: ",
|
||||
Style::default().fg(Color::DarkGray),
|
||||
)),
|
||||
Cell::from(Span::styled(
|
||||
env!("VERGEN_RUSTC_SEMVER"),
|
||||
Style::default().fg(Color::LightYellow),
|
||||
)),
|
||||
Cell::from(Span::styled(
|
||||
" (",
|
||||
Style::default().fg(Color::DarkGray),
|
||||
)),
|
||||
Cell::from(Span::styled(
|
||||
env!("VERGEN_BUILD_DATE"),
|
||||
Style::default().fg(Color::LightYellow),
|
||||
)),
|
||||
Cell::from(Span::styled(
|
||||
")",
|
||||
Style::default().fg(Color::DarkGray),
|
||||
)),
|
||||
]);
|
||||
|
||||
let current_dir_row = Row::new(vec![
|
||||
Cell::from(Span::styled(
|
||||
"current directory: ",
|
||||
Style::default().fg(Color::DarkGray),
|
||||
)),
|
||||
Cell::from(Span::styled(
|
||||
std::env::current_dir()
|
||||
.expect("Could not get current directory")
|
||||
.display()
|
||||
.to_string(),
|
||||
Style::default().fg(Color::LightYellow),
|
||||
)),
|
||||
]);
|
||||
|
||||
let current_channel_row = Row::new(vec![
|
||||
Cell::from(Span::styled(
|
||||
"current channel: ",
|
||||
Style::default().fg(Color::DarkGray),
|
||||
)),
|
||||
Cell::from(Span::styled(
|
||||
self.current_channel().to_string(),
|
||||
Style::default().fg(Color::LightYellow),
|
||||
)),
|
||||
]);
|
||||
|
||||
let current_mode_row = Row::new(vec![
|
||||
Cell::from(Span::styled(
|
||||
"current mode: ",
|
||||
Style::default().fg(Color::DarkGray),
|
||||
)),
|
||||
Cell::from(Span::styled(
|
||||
self.mode.to_string(),
|
||||
Style::default().fg(Color::LightYellow),
|
||||
)),
|
||||
]);
|
||||
|
||||
let widths = vec![Constraint::Fill(1), Constraint::Fill(2)];
|
||||
|
||||
Table::new(
|
||||
vec![
|
||||
version_row,
|
||||
target_triple_row,
|
||||
build_row,
|
||||
current_dir_row,
|
||||
current_channel_row,
|
||||
current_mode_row,
|
||||
],
|
||||
widths,
|
||||
)
|
||||
}
|
||||
}
|
@ -224,7 +224,7 @@ fn impl_unit_channel(ast: &syn::DeriveInput) -> TokenStream {
|
||||
|
||||
// Generate a unit enum from the given enum
|
||||
let unit_enum = quote! {
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Display)]
|
||||
pub enum UnitChannel {
|
||||
#(
|
||||
#variant_names,
|
||||
|
Loading…
x
Reference in New Issue
Block a user