1use std::sync::mpsc::Receiver;
2
3use cursive::{
4 align::HAlign,
5 view::Nameable,
6 views::{Dialog, DialogFocus, LinearLayout, NamedView, ProgressBar, TextView},
7 Cursive,
8};
9
10use crate::{
11 error::{InstallerError, InstallerErrorKind},
12 locale::Locale,
13};
14
15pub enum GuidedDialogButton<T> {
16 Exit,
17 Next(T),
18}
19
20impl<T> GuidedDialogButton<T> {
21 pub fn unwrap_button(self) -> Result<T, InstallerError> {
22 match self {
23 GuidedDialogButton::Exit => Err(InstallerErrorKind::InterruptedByUser.into()),
24 GuidedDialogButton::Next(value) => Ok(value),
25 }
26 }
27}
28
29pub fn guided_dialog<T, F>(
30 locale: &Locale,
31 title: &str,
32 value_callback: F,
33) -> (Dialog, Receiver<GuidedDialogButton<T>>)
34where
35 F: Fn(&mut Cursive) -> T + Send + Sync + 'static,
36 T: Send + 'static,
37{
38 let (sender, receiver) = std::sync::mpsc::sync_channel(1);
39 let sender2 = sender.clone();
40
41 let exit_text = locale.text("button-exit");
42 let next_text = locale.text("button-next");
43
44 let mut dialog = Dialog::new().title(title).h_align(HAlign::Right);
45
46 dialog.add_button(exit_text, move |cursive| {
47 cursive.pop_layer();
48 sender.send(GuidedDialogButton::Exit).unwrap();
49 });
50 dialog.add_button(next_text, move |cursive| {
51 cursive.pop_layer();
52 let value = value_callback(cursive);
53 sender2.send(GuidedDialogButton::Next(value)).unwrap();
54 });
55
56 let _ = dialog.set_focus(DialogFocus::Button(1));
57
58 (dialog, receiver)
59}
60
61pub fn info_dialog(locale: &Locale, title: &str) -> (Dialog, Receiver<()>) {
62 let (sender, receiver) = std::sync::mpsc::sync_channel(1);
63
64 let button_text = locale.text("button-ok");
65
66 let dialog = Dialog::new()
67 .title(title)
68 .button(button_text, move |cursive| {
69 cursive.pop_layer();
70 sender.send(()).unwrap();
71 })
72 .h_align(HAlign::Center);
73
74 (dialog, receiver)
75}
76
77const PROGRESS_DIALOG: &str = "progress_dialog";
78const PROGRESS_DIALOG_TEXT: &str = "progress_dialog_text";
79const PROGRESS_DIALOG_SUBTEXT: &str = "progress_dialog_subtext";
80const PROGRESS_DIALOG_PROGRESS_BAR: &str = "progress_dialog_progress_bar";
81
82pub fn progress_dialog(title: &str) -> NamedView<Dialog> {
83 let layout = LinearLayout::vertical()
84 .child(TextView::empty().with_name(PROGRESS_DIALOG_TEXT))
85 .child(TextView::empty().with_name(PROGRESS_DIALOG_SUBTEXT))
86 .child(ProgressBar::new().with_name(PROGRESS_DIALOG_PROGRESS_BAR));
87
88 Dialog::new()
89 .title(title)
90 .content(layout)
91 .with_name(PROGRESS_DIALOG)
92}
93
94pub fn set_progress_dialog_text(cursive: &mut Cursive, value: &str) {
95 if let Some(mut text_view) = cursive.find_name::<TextView>(PROGRESS_DIALOG_TEXT) {
96 text_view.set_content(value);
97 }
98}
99
100pub fn update_progress_dialog_bar(cursive: &mut Cursive, current: u64, total: u64) {
101 if let Some(mut progress_bar) = cursive.find_name::<ProgressBar>(PROGRESS_DIALOG_PROGRESS_BAR) {
102 progress_bar.set_max(total as usize);
103 progress_bar.set_value(current as usize);
104 }
105}
106
107pub fn dismiss_progress_dialog(cursive: &mut Cursive) {
108 if let Some(position) = cursive.screen_mut().find_layer_from_name(PROGRESS_DIALOG) {
109 cursive.screen_mut().remove_layer(position);
110 }
111}