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
| | // SPDX-License-Identifier: EUPL-1.2+
// SPDX-FileCopyrightText: 2025 Johannes Süllner <johannes.suellner@mailbox.org>
use super::{BUTTON_TEXT_SIZE, Event, MARGIN_VERTICAL, Page, TITLE_TEXT_SIZE, UpdateResult};
use crate::{center_horizontal_in_container, center_in_container};
use iced::{
Element, Task,
widget::{column, qr_code, space, text},
window,
};
use std::process::Command;
const S6_HPR_PATH: &str = "/bin/s6-linux-init-hpr";
const QR_CODE_SIZE: u32 = 350;
const MAX_QR_CODE_LOG_LENGTH: usize = 2000; // The QR code can't contain much more data.
pub struct PageCompletion {
install_result: super::InstallResult,
qr_data_result: Option<Result<qr_code::Data, qr_code::Error>>,
}
impl PageCompletion {
pub fn new(install_result: super::InstallResult) -> Self {
let qr_data_result = match install_result.clone() {
Ok(_) => None,
Err((code, log)) => {
let log_len = log.len();
Some(qr_code::Data::new(
format!(
"Error code: {}\nLog:\n{}",
code,
if log_len > MAX_QR_CODE_LOG_LENGTH {
&log[(log_len - MAX_QR_CODE_LOG_LENGTH)..]
} else {
&log
}
)
.as_bytes(),
))
}
};
Self {
install_result,
qr_data_result,
}
}
}
#[derive(Clone, Debug)]
pub enum PageCompletionEvent {
Quit,
Poweroff,
Reboot,
}
impl PageCompletion {
fn spawn_s6_hpr(parameter: &str) {
let _ = Command::new(S6_HPR_PATH).arg(parameter).spawn();
}
}
impl Page for PageCompletion {
fn update(&mut self, event: Event) -> UpdateResult {
if let Event::PageCompletion(page_completion_event) = event {
match page_completion_event {
PageCompletionEvent::Quit => {
return (None, window::latest().and_then(window::close));
}
PageCompletionEvent::Poweroff => {
Self::spawn_s6_hpr("-p");
}
PageCompletionEvent::Reboot => {
Self::spawn_s6_hpr("-r");
}
}
};
(None, Task::none())
}
fn view(&self) -> Element<'_, Event> {
let main_element = match &self.install_result {
Ok(_) => {
center_in_container!(text("Spectrum installation succeeded!").size(TITLE_TEXT_SIZE))
.into()
}
Err(_) => {
let mut widgets = column![
space().height(MARGIN_VERTICAL),
center_horizontal_in_container!(
text("Spectrum installation failed :(").size(TITLE_TEXT_SIZE)
),
space().height(MARGIN_VERTICAL),
center_horizontal_in_container!(text(format!(
"You can reach out to the team via Chat or the public mailing list\n\
(discuss@spectrum-os.org).\n\
See https://spectrum-os.org/doc/contributing/communication.html for details.\n\
Scan the QR code to obtain the install log."
))),
];
widgets = if let Some(Ok(qr_data)) = &self.qr_data_result {
widgets.push(center_in_container!(
qr_code(&qr_data).total_size(QR_CODE_SIZE)
))
} else {
widgets.push(center_horizontal_in_container!(text(
"Error encoding QR code."
)))
};
widgets.into()
}
};
super::layout::bottom_buttons_layout(
[
vec![
(
text("Reboot").size(BUTTON_TEXT_SIZE).into(),
Some(Event::PageCompletion(PageCompletionEvent::Reboot)),
),
(
text("Poweroff").size(BUTTON_TEXT_SIZE).into(),
Some(Event::PageCompletion(PageCompletionEvent::Poweroff)),
),
],
vec![(
text("Quit installer, stay in live environment")
.size(BUTTON_TEXT_SIZE)
.into(),
Some(Event::PageCompletion(PageCompletionEvent::Quit)),
)],
],
main_element,
)
}
}
|