From 2199ff654e9aac2274a115eaf87c28eace6c35dc Mon Sep 17 00:00:00 2001 From: Raunak Kumar Date: Fri, 13 Mar 2026 04:25:30 +0000 Subject: [PATCH] Refactor: split all rendering logic into ui module --- src/main.rs | 12 +- src/ui.rs | 275 ------------------ src/ui/bitcoin.rs | 58 ++++ src/ui/file_explorer.rs | 39 +++ src/ui/home.rs | 17 ++ src/ui/mod.rs | 86 ++++++ src/ui/p2poolv2.rs | 75 +++++ ...pdm__ui__tests__bitcoin_screen_render.snap | 44 +++ .../pdm__ui__tests__home_screen_render.snap | 44 +++ .../pdm__ui__tests__p2pool_screen_render.snap | 44 +++ 10 files changed, 413 insertions(+), 281 deletions(-) delete mode 100644 src/ui.rs create mode 100644 src/ui/bitcoin.rs create mode 100644 src/ui/file_explorer.rs create mode 100644 src/ui/home.rs create mode 100644 src/ui/mod.rs create mode 100644 src/ui/p2poolv2.rs create mode 100644 src/ui/snapshots/pdm__ui__tests__bitcoin_screen_render.snap create mode 100644 src/ui/snapshots/pdm__ui__tests__home_screen_render.snap create mode 100644 src/ui/snapshots/pdm__ui__tests__p2pool_screen_render.snap diff --git a/src/main.rs b/src/main.rs index 355f2e9..45975fa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,7 +6,7 @@ use p2poolv2_config::Config as P2PoolConfig; use pdm::app::AppAction; use pdm::app::{App, CurrentScreen}; use pdm::config::parse_config as parse_bitcoin_config; -use pdm::ui; +use pdm::ui::ui; use anyhow::Result; use crossterm::{ @@ -43,7 +43,7 @@ fn main() -> Result<()> { fn run_app(terminal: &mut Terminal, app: &mut App) -> Result<()> { loop { - terminal.draw(|f| ui::ui(f, app))?; + terminal.draw(|f| ui(f, app))?; if let Event::Key(key) = event::read()? { if key.kind != KeyEventKind::Press { @@ -167,14 +167,14 @@ mod tests { let mut app = App::new(); // Initial render - terminal.draw(|f| ui::ui(f, &mut app)).unwrap(); + terminal.draw(|f| ui(f, &mut app)).unwrap(); insta::assert_debug_snapshot!("home_screen", terminal.backend()); // Simulate sidebar move app.sidebar_index = 1; app.toggle_menu(); - terminal.draw(|f| ui::ui(f, &mut app)).unwrap(); + terminal.draw(|f| ui(f, &mut app)).unwrap(); insta::assert_debug_snapshot!("menu_toggled", terminal.backend()); assert_eq!(app.current_screen, CurrentScreen::BitcoinConfig); @@ -204,7 +204,7 @@ mod tests { handle_action(AppAction::CloseModal, &mut app).unwrap(); assert_eq!(app.current_screen, CurrentScreen::BitcoinConfig); - terminal.draw(|f| ui::ui(f, &mut app)).unwrap(); + terminal.draw(|f| ui(f, &mut app)).unwrap(); } #[test] @@ -246,7 +246,7 @@ mod tests { assert_eq!(app.bitcoin_conf_path, Some(file_path)); - terminal.draw(|f| ui::ui(f, &mut app)).unwrap(); + terminal.draw(|f| ui(f, &mut app)).unwrap(); } #[test] diff --git a/src/ui.rs b/src/ui.rs deleted file mode 100644 index c83c3ea..0000000 --- a/src/ui.rs +++ /dev/null @@ -1,275 +0,0 @@ -// SPDX-FileCopyrightText: 2024 PDM Authors -// -// SPDX-License-Identifier: AGPL-3.0-or-later - -use crate::app::{App, CurrentScreen}; -use ratatui::{ - prelude::*, - widgets::{Block, Borders, List, ListItem, ListState, Paragraph, Wrap}, -}; - -pub fn ui(f: &mut Frame, app: &mut App) { - let chunks = Layout::default() - .direction(Direction::Horizontal) - .constraints([ - Constraint::Length(25), // Sidebar - Constraint::Min(0), // Main Content - ]) - .split(f.area()); - - // Sidebar - let items = vec![ - ListItem::new("Home"), - ListItem::new("Bitcoin Config"), - ListItem::new("P2Pool Config"), - ]; - - // Highlight the active one - let mut state = ListState::default(); - state.select(Some(app.sidebar_index)); - - let sidebar = List::new(items) - .block(Block::default().borders(Borders::ALL).title(" PDM ")) - .highlight_style(Style::default().bg(Color::Gray).fg(Color::Black)); - - f.render_stateful_widget(sidebar, chunks[0], &mut state); - - // Main Content - let main_area = chunks[1]; - - match app.current_screen { - CurrentScreen::Home => { - let p = Paragraph::new("Welcome to PDM.\n\nSelect a config from the sidebar to edit.") - .block(Block::default().borders(Borders::ALL).title(" Home ")) - .wrap(Wrap { trim: true }); - f.render_widget(p, main_area); - } - CurrentScreen::BitcoinConfig => { - if app.bitcoin_conf_path.is_some() { - render_bitcoin_view(f, app, main_area); - } else { - let p = Paragraph::new("Press [Enter] to select a bitcoin.conf file").block( - Block::default() - .borders(Borders::ALL) - .title(" Bitcoin Config "), - ); - f.render_widget(p, main_area); - } - } - - CurrentScreen::P2PoolConfig => { - if app.p2pool_conf_path.is_some() { - render_p2pool_view(f, app, main_area); - } else { - let p = Paragraph::new("Press [Enter] to select a p2poolv2 config file").block( - Block::default() - .borders(Borders::ALL) - .title(" P2Pool Config "), - ); - f.render_widget(p, main_area); - } - } - CurrentScreen::FileExplorer => { - render_file_explorer(f, app, main_area); - } - _ => {} - } -} - -fn render_file_explorer(f: &mut Frame, app: &mut App, area: Rect) { - let files: Vec = app - .explorer - .files - .iter() - .map(|path| { - let name = path.file_name().unwrap_or_default().to_string_lossy(); - let display_name = if path.is_dir() { - format!("πŸ“ {}", name) - } else { - format!("πŸ“„ {}", name) - }; - ListItem::new(display_name) - }) - .collect(); - - let mut state = ListState::default(); - state.select(Some(app.explorer.selected_index)); - - let title = format!(" Select File (Current: {:?}) ", app.explorer.current_dir); - - let list = List::new(files) - .block(Block::default().borders(Borders::ALL).title(title)) - .highlight_style(Style::default().bg(Color::Blue).fg(Color::White)) - .highlight_symbol(">> "); - - f.render_stateful_widget(list, area, &mut state); -} - -fn render_p2pool_view(f: &mut Frame, app: &mut App, area: Rect) { - let mut items: Vec = Vec::new(); - - if let Some(cfg) = &app.p2pool_config { - // STRATUM - items.push(ListItem::new(Line::from(vec![ - Span::styled("[stratum] ", Style::default().fg(Color::Blue)), - Span::raw(format!("hostname = {}", cfg.stratum.hostname)), - ]))); - - items.push(ListItem::new(Line::from(vec![ - Span::styled("[stratum] ", Style::default().fg(Color::Blue)), - Span::raw(format!("port = {}", cfg.stratum.port)), - ]))); - - items.push(ListItem::new(Line::from(vec![ - Span::styled("[stratum] ", Style::default().fg(Color::Blue)), - Span::raw(format!( - "start_difficulty = {}", - cfg.stratum.start_difficulty - )), - ]))); - - items.push(ListItem::new(Line::from(vec![ - Span::styled("[stratum] ", Style::default().fg(Color::Blue)), - Span::raw(format!( - "minimum_difficulty = {}", - cfg.stratum.minimum_difficulty - )), - ]))); - - // BITCOIN RPC - items.push(ListItem::new(Line::from(vec![ - Span::styled("[bitcoinrpc] ", Style::default().fg(Color::Blue)), - Span::raw(format!("url = {}", cfg.bitcoinrpc.url)), - ]))); - - items.push(ListItem::new(Line::from(vec![ - Span::styled("[bitcoinrpc] ", Style::default().fg(Color::Blue)), - Span::raw(format!("username = {}", cfg.bitcoinrpc.username)), - ]))); - - // NETWORK - items.push(ListItem::new(Line::from(vec![ - Span::styled("[network] ", Style::default().fg(Color::Blue)), - Span::raw(format!("listen_address = {}", cfg.network.listen_address)), - ]))); - - items.push(ListItem::new(Line::from(vec![ - Span::styled("[network] ", Style::default().fg(Color::Blue)), - Span::raw(format!( - "max_established_incoming = {}", - cfg.network.max_established_incoming - )), - ]))); - - // STORE - items.push(ListItem::new(Line::from(vec![ - Span::styled("[store] ", Style::default().fg(Color::Blue)), - Span::raw(format!("path = {}", cfg.store.path)), - ]))); - - // API - items.push(ListItem::new(Line::from(vec![ - Span::styled("[api] ", Style::default().fg(Color::Blue)), - Span::raw(format!("hostname = {}", cfg.api.hostname)), - ]))); - - items.push(ListItem::new(Line::from(vec![ - Span::styled("[api] ", Style::default().fg(Color::Blue)), - Span::raw(format!("port = {}", cfg.api.port)), - ]))); - } - - let list = List::new(items).block( - Block::default() - .borders(Borders::ALL) - .title(" P2Pool Configuration "), - ); - - f.render_widget(list, area); -} - -fn render_bitcoin_view(f: &mut Frame, app: &mut App, area: Rect) { - let items: Vec = app - .bitcoin_data - .iter() - .map(|entry| { - let style = if entry.enabled { - Style::default() - .fg(Color::White) - .add_modifier(Modifier::BOLD) - } else { - Style::default().fg(Color::DarkGray) - }; - - let content = Line::from(vec![ - Span::styled(format!("{} = ", entry.key), style), - Span::styled(&entry.value, style), - if !entry.enabled { - Span::styled(" (disabled)", style) - } else { - Span::raw("") - }, - ]); - - ListItem::new(content) - }) - .collect(); - - let list = List::new(items) - .block( - Block::default() - .borders(Borders::ALL) - .title(" Bitcoin Configuration "), - ) - .highlight_style(Style::default().bg(Color::Yellow)); - - f.render_widget(list, area); -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::app::App; - use ratatui::Terminal; - use ratatui::backend::TestBackend; - - #[test] - fn test_home_screen_render() { - let backend = TestBackend::new(80, 20); - let mut terminal = Terminal::new(backend).unwrap(); - - let mut app = App::new(); - - terminal.draw(|f| ui(f, &mut app)).unwrap(); - - insta::assert_debug_snapshot!(terminal.backend()); - } - - #[test] - fn test_bitcoin_screen_render() { - let backend = TestBackend::new(80, 20); - let mut terminal = Terminal::new(backend).unwrap(); - - let mut app = App::new(); - app.sidebar_index = 1; - app.toggle_menu(); - - terminal.draw(|f| ui(f, &mut app)).unwrap(); - - insta::assert_debug_snapshot!(terminal.backend()); - } - - #[test] - fn test_p2pool_screen_render() { - let backend = TestBackend::new(80, 20); - let mut terminal = Terminal::new(backend).unwrap(); - - let mut app = App::new(); - app.sidebar_index = 2; - app.toggle_menu(); - - terminal.draw(|f| ui(f, &mut app)).unwrap(); - - insta::assert_debug_snapshot!(terminal.backend()); - } -} diff --git a/src/ui/bitcoin.rs b/src/ui/bitcoin.rs new file mode 100644 index 0000000..0307fd0 --- /dev/null +++ b/src/ui/bitcoin.rs @@ -0,0 +1,58 @@ +// SPDX-FileCopyrightText: 2024 PDM Authors +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +use crate::app::App; +use ratatui::{ + prelude::*, + widgets::{Block, Borders, List, ListItem, Paragraph}, +}; + +// Render the bitcoin config view when no config is loaded yet. +pub fn render(f: &mut Frame, app: &mut App, area: Rect) { + if app.bitcoin_conf_path.is_none() { + let p = Paragraph::new("Press [Enter] to select a bitcoin.conf file").block( + Block::default() + .borders(Borders::ALL) + .title(" Bitcoin Config "), + ); + f.render_widget(p, area); + return; + } + + let items: Vec = app + .bitcoin_data + .iter() + .map(|entry| { + let style = if entry.enabled { + Style::default() + .fg(Color::White) + .add_modifier(Modifier::BOLD) + } else { + Style::default().fg(Color::DarkGray) + }; + + let content = Line::from(vec![ + Span::styled(format!("{} = ", entry.key), style), + Span::styled(&entry.value, style), + if !entry.enabled { + Span::styled(" (disabled)", style) + } else { + Span::raw("") + }, + ]); + + ListItem::new(content) + }) + .collect(); + + let list = List::new(items) + .block( + Block::default() + .borders(Borders::ALL) + .title(" Bitcoin Configuration "), + ) + .highlight_style(Style::default().bg(Color::Yellow)); + + f.render_widget(list, area); +} diff --git a/src/ui/file_explorer.rs b/src/ui/file_explorer.rs new file mode 100644 index 0000000..01b8810 --- /dev/null +++ b/src/ui/file_explorer.rs @@ -0,0 +1,39 @@ +// SPDX-FileCopyrightText: 2024 PDM Authors +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +use crate::app::App; +use ratatui::{ + prelude::*, + widgets::{Block, Borders, List, ListItem, ListState}, +}; + +// Render the file picker with the current directory and active selection. +pub fn render(f: &mut Frame, app: &mut App, area: Rect) { + let files: Vec = app + .explorer + .files + .iter() + .map(|path| { + let name = path.file_name().unwrap_or_default().to_string_lossy(); + let display_name = if path.is_dir() { + format!("πŸ“ {}", name) + } else { + format!("πŸ“„ {}", name) + }; + ListItem::new(display_name) + }) + .collect(); + + let mut state = ListState::default(); + state.select(Some(app.explorer.selected_index)); + + let title = format!(" Select File (Current: {:?}) ", app.explorer.current_dir); + + let list = List::new(files) + .block(Block::default().borders(Borders::ALL).title(title)) + .highlight_style(Style::default().bg(Color::Blue).fg(Color::White)) + .highlight_symbol(">> "); + + f.render_stateful_widget(list, area, &mut state); +} diff --git a/src/ui/home.rs b/src/ui/home.rs new file mode 100644 index 0000000..dc1ffda --- /dev/null +++ b/src/ui/home.rs @@ -0,0 +1,17 @@ +// SPDX-FileCopyrightText: 2024 PDM Authors +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +use crate::app::App; +use ratatui::{ + prelude::*, + widgets::{Block, Borders, Paragraph, Wrap}, +}; + +// Render the default home screen shown before the user opens a config. +pub fn render(f: &mut Frame, _app: &mut App, area: Rect) { + let p = Paragraph::new("Welcome to PDM.\n\nSelect a config from the sidebar to edit.") + .block(Block::default().borders(Borders::ALL).title(" Home ")) + .wrap(Wrap { trim: true }); + f.render_widget(p, area); +} diff --git a/src/ui/mod.rs b/src/ui/mod.rs new file mode 100644 index 0000000..7c6c759 --- /dev/null +++ b/src/ui/mod.rs @@ -0,0 +1,86 @@ +// SPDX-FileCopyrightText: 2024 PDM Authors +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +mod bitcoin; +mod file_explorer; +mod home; +mod p2poolv2; + +use crate::app::{App, CurrentScreen}; +use ratatui::{ + prelude::*, + widgets::{Block, Borders, List, ListItem, ListState}, +}; + +// Render the sidebar and dispatch the active content pane for the current screen +pub fn ui(f: &mut Frame, app: &mut App) { + let chunks = Layout::default() + .direction(Direction::Horizontal) + .constraints([Constraint::Length(25), Constraint::Min(0)]) + .split(f.area()); + + let items = vec![ + ListItem::new("Home"), + ListItem::new("Bitcoin Config"), + ListItem::new("P2Pool Config"), + ]; + + let mut state = ListState::default(); + state.select(Some(app.sidebar_index)); + + let sidebar = List::new(items) + .block(Block::default().borders(Borders::ALL).title(" PDM ")) + .highlight_style(Style::default().bg(Color::Gray).fg(Color::Black)); + + f.render_stateful_widget(sidebar, chunks[0], &mut state); + + let main_area = chunks[1]; + + match app.current_screen { + CurrentScreen::Home => home::render(f, app, main_area), + CurrentScreen::BitcoinConfig => bitcoin::render(f, app, main_area), + CurrentScreen::P2PoolConfig => p2poolv2::render(f, app, main_area), + CurrentScreen::FileExplorer => file_explorer::render(f, app, main_area), + _ => {} + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::app::App; + use ratatui::Terminal; + use ratatui::backend::TestBackend; + + #[test] + fn test_home_screen_render() { + let backend = TestBackend::new(80, 20); + let mut terminal = Terminal::new(backend).unwrap(); + let mut app = App::new(); + terminal.draw(|f| ui(f, &mut app)).unwrap(); + insta::assert_debug_snapshot!(terminal.backend()); + } + + #[test] + fn test_bitcoin_screen_render() { + let backend = TestBackend::new(80, 20); + let mut terminal = Terminal::new(backend).unwrap(); + let mut app = App::new(); + app.sidebar_index = 1; + app.toggle_menu(); + terminal.draw(|f| ui(f, &mut app)).unwrap(); + insta::assert_debug_snapshot!(terminal.backend()); + } + + #[test] + fn test_p2pool_screen_render() { + let backend = TestBackend::new(80, 20); + let mut terminal = Terminal::new(backend).unwrap(); + let mut app = App::new(); + app.sidebar_index = 2; + app.toggle_menu(); + terminal.draw(|f| ui(f, &mut app)).unwrap(); + insta::assert_debug_snapshot!(terminal.backend()); + } +} diff --git a/src/ui/p2poolv2.rs b/src/ui/p2poolv2.rs new file mode 100644 index 0000000..754fc7d --- /dev/null +++ b/src/ui/p2poolv2.rs @@ -0,0 +1,75 @@ +// SPDX-FileCopyrightText: 2024 PDM Authors +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +use crate::app::App; +use ratatui::{ + prelude::*, + widgets::{Block, Borders, List, ListItem, Paragraph}, +}; + +// Render the parsed p2pool view until a config file is selected. +pub fn render(f: &mut Frame, app: &mut App, area: Rect) { + if app.p2pool_conf_path.is_none() { + let p = Paragraph::new("Press [Enter] to select a p2poolv2 config file").block( + Block::default() + .borders(Borders::ALL) + .title(" P2Pool Config "), + ); + f.render_widget(p, area); + return; + } + + let mut items: Vec = Vec::new(); + + if let Some(cfg) = &app.p2pool_config { + let blue = Style::default().fg(Color::Blue); + + let fields: &[(&str, String)] = &[ + ("[stratum] ", format!("hostname = {}", cfg.stratum.hostname)), + ("[stratum] ", format!("port = {}", cfg.stratum.port)), + ( + "[stratum] ", + format!("start_difficulty = {}", cfg.stratum.start_difficulty), + ), + ( + "[stratum] ", + format!("minimum_difficulty = {}", cfg.stratum.minimum_difficulty), + ), + ("[bitcoinrpc] ", format!("url = {}", cfg.bitcoinrpc.url)), + ( + "[bitcoinrpc] ", + format!("username = {}", cfg.bitcoinrpc.username), + ), + ( + "[network] ", + format!("listen_address = {}", cfg.network.listen_address), + ), + ( + "[network] ", + format!( + "max_established_incoming = {}", + cfg.network.max_established_incoming + ), + ), + ("[store] ", format!("path = {}", cfg.store.path)), + ("[api] ", format!("hostname = {}", cfg.api.hostname)), + ("[api] ", format!("port = {}", cfg.api.port)), + ]; + + for (section, value) in fields { + items.push(ListItem::new(Line::from(vec![ + Span::styled(*section, blue), + Span::raw(value.clone()), + ]))); + } + } + + let list = List::new(items).block( + Block::default() + .borders(Borders::ALL) + .title(" P2Pool Configuration "), + ); + + f.render_widget(list, area); +} diff --git a/src/ui/snapshots/pdm__ui__tests__bitcoin_screen_render.snap b/src/ui/snapshots/pdm__ui__tests__bitcoin_screen_render.snap new file mode 100644 index 0000000..bffa628 --- /dev/null +++ b/src/ui/snapshots/pdm__ui__tests__bitcoin_screen_render.snap @@ -0,0 +1,44 @@ +--- +source: src/ui/mod.rs +expression: terminal.backend() +--- +TestBackend { + buffer: Buffer { + area: Rect { x: 0, y: 0, width: 80, height: 20 }, + content: [ + "β”Œ PDM β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”Œ Bitcoin Config ─────────────────────────────────────┐", + "β”‚Home β”‚β”‚Press [Enter] to select a bitcoin.conf file β”‚", + "β”‚Bitcoin Config β”‚β”‚ β”‚", + "β”‚P2Pool Config β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜", + ], + styles: [ + x: 0, y: 0, fg: Reset, bg: Reset, underline: Reset, modifier: NONE, + x: 1, y: 2, fg: Black, bg: Gray, underline: Reset, modifier: NONE, + x: 24, y: 2, fg: Reset, bg: Reset, underline: Reset, modifier: NONE, + ] + }, + scrollback: Buffer { + area: Rect { x: 0, y: 0, width: 80, height: 0 } + }, + cursor: false, + pos: ( + 0, + 0, + ), +} diff --git a/src/ui/snapshots/pdm__ui__tests__home_screen_render.snap b/src/ui/snapshots/pdm__ui__tests__home_screen_render.snap new file mode 100644 index 0000000..3e26dd8 --- /dev/null +++ b/src/ui/snapshots/pdm__ui__tests__home_screen_render.snap @@ -0,0 +1,44 @@ +--- +source: src/ui/mod.rs +expression: terminal.backend() +--- +TestBackend { + buffer: Buffer { + area: Rect { x: 0, y: 0, width: 80, height: 20 }, + content: [ + "β”Œ PDM β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”Œ Home ───────────────────────────────────────────────┐", + "β”‚Home β”‚β”‚Welcome to PDM. β”‚", + "β”‚Bitcoin Config β”‚β”‚ β”‚", + "β”‚P2Pool Config β”‚β”‚Select a config from the sidebar to edit. β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜", + ], + styles: [ + x: 0, y: 0, fg: Reset, bg: Reset, underline: Reset, modifier: NONE, + x: 1, y: 1, fg: Black, bg: Gray, underline: Reset, modifier: NONE, + x: 24, y: 1, fg: Reset, bg: Reset, underline: Reset, modifier: NONE, + ] + }, + scrollback: Buffer { + area: Rect { x: 0, y: 0, width: 80, height: 0 } + }, + cursor: false, + pos: ( + 0, + 0, + ), +} diff --git a/src/ui/snapshots/pdm__ui__tests__p2pool_screen_render.snap b/src/ui/snapshots/pdm__ui__tests__p2pool_screen_render.snap new file mode 100644 index 0000000..4b6b2ed --- /dev/null +++ b/src/ui/snapshots/pdm__ui__tests__p2pool_screen_render.snap @@ -0,0 +1,44 @@ +--- +source: src/ui/mod.rs +expression: terminal.backend() +--- +TestBackend { + buffer: Buffer { + area: Rect { x: 0, y: 0, width: 80, height: 20 }, + content: [ + "β”Œ PDM β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”Œ P2Pool Config ──────────────────────────────────────┐", + "β”‚Home β”‚β”‚Press [Enter] to select a p2poolv2 config file β”‚", + "β”‚Bitcoin Config β”‚β”‚ β”‚", + "β”‚P2Pool Config β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β”‚ β”‚β”‚ β”‚", + "β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜", + ], + styles: [ + x: 0, y: 0, fg: Reset, bg: Reset, underline: Reset, modifier: NONE, + x: 1, y: 3, fg: Black, bg: Gray, underline: Reset, modifier: NONE, + x: 24, y: 3, fg: Reset, bg: Reset, underline: Reset, modifier: NONE, + ] + }, + scrollback: Buffer { + area: Rect { x: 0, y: 0, width: 80, height: 0 } + }, + cursor: false, + pos: ( + 0, + 0, + ), +}