Skip to main content

quickswitch/services/
global_preview_state.rs

1use crate::utils::FileItem;
2use super::preview::PreviewContent;
3use ratatui::{
4    style::{Color, Style},
5    text::{Line, Span},
6};
7
8/// Preview state that can be owned directly by AppState
9#[derive(Debug, Clone)]
10pub struct PreviewState {
11    pub content: PreviewContent,
12    pub title: String,
13    pub scroll_offset: usize,
14    pub current_file_item: Option<FileItem>,
15}
16
17impl Default for PreviewState {
18    fn default() -> Self {
19        Self {
20            content: PreviewContent::text(vec![Line::from(vec![Span::styled(
21                "No file selected".to_string(),
22                Style::default().fg(Color::Gray),
23            )])]),
24            title: "Preview".to_string(),
25            scroll_offset: 0,
26            current_file_item: None,
27        }
28    }
29}
30
31impl PreviewState {
32    pub fn new() -> Self {
33        Self::default()
34    }
35
36    pub fn set_current_file_item(&mut self, path: Option<FileItem>) {
37        self.current_file_item = path;
38    }
39
40    pub fn get_current_file_item(&self) -> Option<FileItem> {
41        self.current_file_item.clone()
42    }
43
44    pub fn update_preview(
45        &mut self,
46        title: String,
47        content: PreviewContent,
48        file_item: Option<FileItem>,
49    ) {
50        // Now using channel means by the time it arrives, it might be outdated
51        if file_item != self.get_current_file_item() {
52            return;
53        }
54        self.title = title;
55        self.content = content;
56        self.scroll_offset = 0;
57    }
58
59    pub fn clear_preview(&mut self) {
60        self.title = "Preview".to_string();
61        self.content = PreviewContent::text(vec![Line::from(vec![Span::styled(
62            "No file selected".to_string(),
63            Style::default().fg(Color::Gray),
64        )])]);
65        self.scroll_offset = 0;
66    }
67
68    pub fn get_title(&self) -> String {
69        self.title.clone()
70    }
71
72    pub fn get_content(&self) -> PreviewContent {
73        self.content.clone()
74    }
75
76    pub fn get_scroll_offset(&self) -> usize {
77        self.scroll_offset
78    }
79
80    pub fn set_scroll_offset(&mut self, offset: usize) {
81        self.scroll_offset = offset;
82    }
83
84    pub fn scroll_up(&mut self) -> bool {
85        if self.scroll_offset > 0 {
86            self.scroll_offset -= 1;
87            true
88        } else {
89            false
90        }
91    }
92
93    pub fn scroll_down(&mut self) -> bool {
94        if self.scroll_offset + 1 < self.content.len() {
95            self.scroll_offset += 1;
96            true
97        } else {
98            false
99        }
100    }
101
102    pub fn scroll_page_up(&mut self, visible_height: usize) -> bool {
103        let half_screen = (visible_height / 2).max(1);
104        let new_offset = self.scroll_offset.saturating_sub(half_screen);
105        if new_offset != self.scroll_offset {
106            self.scroll_offset = new_offset;
107            true
108        } else {
109            false
110        }
111    }
112
113    pub fn scroll_page_down(&mut self, visible_height: usize) -> bool {
114        let half_screen = (visible_height / 2).max(1);
115        let max_offset = self.content.len().saturating_sub(visible_height);
116        let new_offset = (self.scroll_offset + half_screen).min(max_offset);
117        if new_offset != self.scroll_offset {
118            self.scroll_offset = new_offset;
119            true
120        } else {
121            false
122        }
123    }
124
125    pub fn reset_scroll(&mut self) {
126        self.scroll_offset = 0;
127    }
128}