summaryrefslogtreecommitdiffstats
path: root/src/ui/widgets/tui_worker.rs
blob: 3018ad1d7b410d18e565faacefa37bc33a455ab3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
use ratatui::buffer::Buffer;
use ratatui::layout::Rect;
use ratatui::style::{Color, Modifier, Style};
use ratatui::widgets::Widget;

use crate::context::WorkerContext;
use crate::io::{FileOperationProgress, IoWorkerObserver};
use crate::util::format;

pub struct TuiWorker<'a> {
    pub context: &'a WorkerContext,
}

impl<'a> TuiWorker<'a> {
    pub fn new(context: &'a WorkerContext) -> Self {
        Self { context }
    }
}

impl<'a> Widget for TuiWorker<'a> {
    fn render(self, area: Rect, buf: &mut Buffer) {
        if area.height < 7 {
            return;
        }
        match self.context.worker_ref() {
            Some(io_obs) => {
                if let Some(progress) = io_obs.progress.as_ref() {
                    let current_area = Rect {
                        y: area.y + 1,
                        ..area
                    };
                    TuiCurrentWorker::new(io_obs, progress).render(current_area, buf);
                }

                // draw queued up work
                let style = Style::default()
                    .fg(Color::Yellow)
                    .add_modifier(Modifier::BOLD);
                buf.set_stringn(0, 6, "Queue:", area.width as usize, style);

                let queue_area = Rect {
                    y: area.y + 7,
                    ..area
                };
                TuiWorkerQueue::new(self.context).render(queue_area, buf);
            }
            _ => {
                let style = Style::default();
                buf.set_stringn(0, 2, "No operations running", area.width as usize, style);
                let style = Style::default()
                    .fg(Color::Yellow)
                    .add_modifier(Modifier::BOLD);
                buf.set_stringn(0, 4, "Queue:", area.width as usize, style);
            }
        }
    }
}

pub struct TuiCurrentWorker<'a> {
    pub observer: &'a IoWorkerObserver,
    pub progress: &'a FileOperationProgress,
}

impl<'a> TuiCurrentWorker<'a> {
    pub fn new(observer: &'a IoWorkerObserver, progress: &'a FileOperationProgress) -> Self {
        Self { observer, progress }
    }
}

impl<'a> Widget for TuiCurrentWorker<'a> {
    fn render(self, area: Rect, buf: &mut Buffer) {
        let top = area.top();
        let left = area.left();
        let right = area.right();

        let op_str = self.progress.kind().actioning_str();

        let processed_size = format::file_size_to_string(self.progress.bytes_processed());
        let total_size = format::file_size_to_string(self.progress.total_bytes());

        let msg = format!(
            "{} ({}/{}) ({}/{}) {:?}",
            op_str,
            self.progress.files_processed() + 1,
            self.progress.total_files(),
            processed_size,
            total_size,
            self.observer.dest_path(),
        );
        buf.set_stringn(left, top, msg, right as usize, Style::default());

        if let Some(file_name) = self
            .progress
            .current_file()
            .file_name()
            .map(|s| s.to_string_lossy())
        {
            buf.set_stringn(
                left,
                top + 1,
                format!("{}", file_name),
                right as usize,
                Style::default(),
            );
        }

        // draw a progress bar
        let progress_bar_width = (self.progress.files_processed() as f32
            / self.progress.total_files() as f32
            * area.width as f32) as usize;
        let progress_bar_space = " ".repeat(progress_bar_width);
        let progress_bar_style = Style::default().bg(Color::Blue);
        buf.set_stringn(
            left,
            top + 2,
            progress_bar_space,
            right as usize,
            progress_bar_style,
        );
    }
}

pub struct TuiWorkerQueue<'a> {
    pub context: &'a WorkerContext,
}

impl<'a> TuiWorkerQueue<'a> {
    pub fn new(context: &'a WorkerContext) -> Self {
        Self { context }
    }
}

impl<'a> Widget for TuiWorkerQueue<'a> {
    fn render(self, area: Rect, buf: &mut Buffer) {
        let top = area.top();
        let left = area.left();
        let right = area.right();
        let width = right - left;

        let style = Style::default();

        for (i, worker) in self.context.iter().enumerate() {
            let msg = format!(
                "{:02} {} {} items {:?}",
                i + 1,
                worker.kind(),
                worker.paths.len(),
                worker.dest
            );
            buf.set_stringn(left, (top as usize + i) as u16, msg, width as usize, style);
        }
    }
}