mirror of
https://github.com/alexpasmantier/television.git
synced 2025-06-07 03:55:23 +00:00
feat(orientation): add orientation for television #489
This commit is contained in:
parent
be8008e97d
commit
85fe9bb388
@ -50,6 +50,8 @@ show_help_bar = false
|
|||||||
show_preview_panel = true
|
show_preview_panel = true
|
||||||
# Where to place the input bar in the UI (top or bottom)
|
# Where to place the input bar in the UI (top or bottom)
|
||||||
input_bar_position = "top"
|
input_bar_position = "top"
|
||||||
|
# What orientation should tv be (landscape or portrait)
|
||||||
|
orientation = "landscape"
|
||||||
# DEPRECATED: title is now always displayed at the top as part of the border
|
# DEPRECATED: title is now always displayed at the top as part of the border
|
||||||
# Where to place the preview title in the UI (top or bottom)
|
# Where to place the preview title in the UI (top or bottom)
|
||||||
# preview_title_position = "top"
|
# preview_title_position = "top"
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::screen::layout::{InputPosition, PreviewTitlePosition};
|
use crate::screen::layout::{
|
||||||
|
InputPosition, Orientation, PreviewTitlePosition,
|
||||||
|
};
|
||||||
|
|
||||||
use super::themes::DEFAULT_THEME;
|
use super::themes::DEFAULT_THEME;
|
||||||
|
|
||||||
@ -17,6 +19,7 @@ pub struct UiConfig {
|
|||||||
pub show_preview_panel: bool,
|
pub show_preview_panel: bool,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub input_bar_position: InputPosition,
|
pub input_bar_position: InputPosition,
|
||||||
|
pub orientation: Orientation,
|
||||||
pub preview_title_position: Option<PreviewTitlePosition>,
|
pub preview_title_position: Option<PreviewTitlePosition>,
|
||||||
pub theme: String,
|
pub theme: String,
|
||||||
pub custom_header: Option<String>,
|
pub custom_header: Option<String>,
|
||||||
@ -31,6 +34,7 @@ impl Default for UiConfig {
|
|||||||
show_help_bar: false,
|
show_help_bar: false,
|
||||||
show_preview_panel: true,
|
show_preview_panel: true,
|
||||||
input_bar_position: InputPosition::Top,
|
input_bar_position: InputPosition::Top,
|
||||||
|
orientation: Orientation::Landscape,
|
||||||
preview_title_position: None,
|
preview_title_position: None,
|
||||||
theme: String::from(DEFAULT_THEME),
|
theme: String::from(DEFAULT_THEME),
|
||||||
custom_header: None,
|
custom_header: None,
|
||||||
|
@ -241,12 +241,13 @@ pub fn draw(ctx: &Ctx, f: &mut Frame<'_>, area: Rect) -> Result<Layout> {
|
|||||||
&ctx.tv_state.spinner,
|
&ctx.tv_state.spinner,
|
||||||
&ctx.colorscheme,
|
&ctx.colorscheme,
|
||||||
&ctx.config.ui.custom_header,
|
&ctx.config.ui.custom_header,
|
||||||
|
&ctx.config.ui.input_bar_position,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
if layout.preview_window.is_some() {
|
if let Some(preview_rect) = layout.preview_window {
|
||||||
draw_preview_content_block(
|
draw_preview_content_block(
|
||||||
f,
|
f,
|
||||||
layout.preview_window.unwrap(),
|
preview_rect,
|
||||||
&ctx.tv_state.preview_state,
|
&ctx.tv_state.preview_state,
|
||||||
ctx.config.ui.use_nerd_font_icons,
|
ctx.config.ui.use_nerd_font_icons,
|
||||||
&ctx.colorscheme,
|
&ctx.colorscheme,
|
||||||
|
@ -6,12 +6,16 @@ use ratatui::{
|
|||||||
},
|
},
|
||||||
style::{Style, Stylize},
|
style::{Style, Stylize},
|
||||||
text::{Line, Span},
|
text::{Line, Span},
|
||||||
widgets::{Block, BorderType, Borders, ListState, Paragraph},
|
widgets::{
|
||||||
|
block::Position, Block, BorderType, Borders, ListState, Paragraph,
|
||||||
|
},
|
||||||
Frame,
|
Frame,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::screen::{colors::Colorscheme, spinner::Spinner};
|
use crate::screen::{colors::Colorscheme, spinner::Spinner};
|
||||||
|
|
||||||
|
use super::layout::InputPosition;
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn draw_input_box(
|
pub fn draw_input_box(
|
||||||
f: &mut Frame,
|
f: &mut Frame,
|
||||||
@ -25,13 +29,18 @@ pub fn draw_input_box(
|
|||||||
spinner: &Spinner,
|
spinner: &Spinner,
|
||||||
colorscheme: &Colorscheme,
|
colorscheme: &Colorscheme,
|
||||||
custom_header: &Option<String>,
|
custom_header: &Option<String>,
|
||||||
|
input_bar_position: &InputPosition,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let header = custom_header.as_deref().unwrap_or(channel_name);
|
let header = custom_header.as_deref().unwrap_or(channel_name);
|
||||||
let input_block = Block::default()
|
let input_block = Block::default()
|
||||||
.borders(Borders::ALL)
|
.borders(Borders::ALL)
|
||||||
.border_type(BorderType::Rounded)
|
.border_type(BorderType::Rounded)
|
||||||
.border_style(Style::default().fg(colorscheme.general.border_fg))
|
.border_style(Style::default().fg(colorscheme.general.border_fg))
|
||||||
.title_top(
|
.title_position(match input_bar_position {
|
||||||
|
InputPosition::Top => Position::Top,
|
||||||
|
InputPosition::Bottom => Position::Bottom,
|
||||||
|
})
|
||||||
|
.title(
|
||||||
Line::from(String::from(" ") + header + " ")
|
Line::from(String::from(" ") + header + " ")
|
||||||
.style(Style::default().fg(colorscheme.mode.channel).bold())
|
.style(Style::default().fg(colorscheme.mode.channel).bold())
|
||||||
.centered(),
|
.centered(),
|
||||||
|
@ -66,6 +66,17 @@ impl Display for InputPosition {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(
|
||||||
|
Debug, Clone, Copy, Deserialize, Serialize, Default, PartialEq, Hash,
|
||||||
|
)]
|
||||||
|
pub enum Orientation {
|
||||||
|
#[serde(rename = "landscape")]
|
||||||
|
#[default]
|
||||||
|
Landscape,
|
||||||
|
#[serde(rename = "portrait")]
|
||||||
|
Portrait,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(
|
#[derive(
|
||||||
Debug, Clone, Copy, Deserialize, Serialize, Default, PartialEq, Hash,
|
Debug, Clone, Copy, Deserialize, Serialize, Default, PartialEq, Hash,
|
||||||
)]
|
)]
|
||||||
@ -168,26 +179,57 @@ impl Layout {
|
|||||||
help_bar_layout = None;
|
help_bar_layout = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
// split the main block into 1, 2, or 3 vertical chunks
|
let remote_constraints = if show_remote {
|
||||||
// (results + preview + remote)
|
vec![Constraint::Fill(1), Constraint::Length(24)]
|
||||||
let mut constraints = vec![Constraint::Fill(1)];
|
} else {
|
||||||
if show_preview {
|
vec![Constraint::Fill(1)]
|
||||||
constraints.push(Constraint::Fill(1));
|
};
|
||||||
}
|
let remote_chunks = layout::Layout::default()
|
||||||
if show_remote {
|
|
||||||
// in order to fit with the help bar logo
|
|
||||||
constraints.push(Constraint::Length(24));
|
|
||||||
}
|
|
||||||
let vt_chunks = layout::Layout::default()
|
|
||||||
.direction(Direction::Horizontal)
|
.direction(Direction::Horizontal)
|
||||||
.constraints(constraints)
|
.constraints(remote_constraints)
|
||||||
.split(main_rect);
|
.split(main_rect);
|
||||||
|
|
||||||
// left block: results + input field
|
let remote_control = if show_remote {
|
||||||
|
Some(remote_chunks[1])
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
// split the main block into 1 or 2 chunks
|
||||||
|
// (results + preview)
|
||||||
|
let constraints = if show_preview {
|
||||||
|
vec![Constraint::Fill(1), Constraint::Fill(1)]
|
||||||
|
} else {
|
||||||
|
vec![Constraint::Fill(1)]
|
||||||
|
};
|
||||||
|
|
||||||
|
let main_chunks = layout::Layout::default()
|
||||||
|
.direction(match ui_config.orientation {
|
||||||
|
Orientation::Portrait => Direction::Vertical,
|
||||||
|
Orientation::Landscape => Direction::Horizontal,
|
||||||
|
})
|
||||||
|
.constraints(constraints)
|
||||||
|
.split(remote_chunks[0]);
|
||||||
|
|
||||||
|
// result block: results + input field
|
||||||
let results_constraints =
|
let results_constraints =
|
||||||
vec![Constraint::Min(3), Constraint::Length(3)];
|
vec![Constraint::Min(3), Constraint::Length(3)];
|
||||||
|
|
||||||
let left_chunks = layout::Layout::default()
|
let (result_window, preview_window) = if show_preview {
|
||||||
|
match (ui_config.orientation, ui_config.input_bar_position) {
|
||||||
|
(Orientation::Landscape, _)
|
||||||
|
| (Orientation::Portrait, InputPosition::Top) => {
|
||||||
|
(main_chunks[0], Some(main_chunks[1]))
|
||||||
|
}
|
||||||
|
(Orientation::Portrait, InputPosition::Bottom) => {
|
||||||
|
(main_chunks[1], Some(main_chunks[0]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
(main_chunks[0], None)
|
||||||
|
};
|
||||||
|
|
||||||
|
let result_chunks = layout::Layout::default()
|
||||||
.direction(Direction::Vertical)
|
.direction(Direction::Vertical)
|
||||||
.constraints(match ui_config.input_bar_position {
|
.constraints(match ui_config.input_bar_position {
|
||||||
InputPosition::Top => {
|
InputPosition::Top => {
|
||||||
@ -195,25 +237,10 @@ impl Layout {
|
|||||||
}
|
}
|
||||||
InputPosition::Bottom => results_constraints,
|
InputPosition::Bottom => results_constraints,
|
||||||
})
|
})
|
||||||
.split(vt_chunks[0]);
|
.split(result_window);
|
||||||
let (input, results) = match ui_config.input_bar_position {
|
let (input, results) = match ui_config.input_bar_position {
|
||||||
InputPosition::Bottom => (left_chunks[1], left_chunks[0]),
|
InputPosition::Bottom => (result_chunks[1], result_chunks[0]),
|
||||||
InputPosition::Top => (left_chunks[0], left_chunks[1]),
|
InputPosition::Top => (result_chunks[0], result_chunks[1]),
|
||||||
};
|
|
||||||
|
|
||||||
// right block: preview title + preview
|
|
||||||
let mut remote_idx = 1;
|
|
||||||
let preview_window = if show_preview {
|
|
||||||
remote_idx += 1;
|
|
||||||
Some(vt_chunks[1])
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let remote_control = if show_remote {
|
|
||||||
Some(vt_chunks[remote_idx])
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Self::new(
|
Self::new(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user