zng_wgt_setup/page/
eula.rs1use zng_ext_l10n::l10n;
2use zng_wgt::{enabled, margin, on_init, prelude::*};
3use zng_wgt_container::Container;
4use zng_wgt_fill::background_color;
5use zng_wgt_markdown::Markdown;
6use zng_wgt_scroll::{SCROLL, Scroll, ScrollMode};
7use zng_wgt_text::Text;
8use zng_wgt_text_input::selectable::SelectableText;
9use zng_wgt_toggle as toggle;
10use zng_wgt_wizard::Page;
11
12use crate::{APP_NAME_VAR, SETUP_OP_VAR};
13
14#[non_exhaustive]
16pub struct EulaPage {
17 pub license: Var<EulaTxt>,
19
20 pub user_accepts: Var<bool>,
25
26 pub required_scroll: Factor,
34}
35impl EulaPage {
36 pub fn new(license: impl IntoVar<EulaTxt>) -> Self {
38 Self {
39 license: license.into_var(),
40 user_accepts: var(false),
41 required_scroll: 0.fct(),
42 }
43 }
44
45 pub fn build(self) -> Page {
47 let title = l10n!("eula/title", "License Agreement");
48 let info = SETUP_OP_VAR.flat_map(|op| match op {
49 crate::SetupOp::Install => l10n!(
50 "eula/info.install",
51 "Please review the license terms before installing {$app}",
52 app = APP_NAME_VAR
53 ),
54 crate::SetupOp::Update => l10n!(
55 "eula/info.update",
56 "Please review the license terms before updating {$app}",
57 app = APP_NAME_VAR
58 ),
59 crate::SetupOp::Repair | crate::SetupOp::Uninstall => const_var("".into()),
60 });
61
62 let Self {
63 license,
64 user_accepts,
65 required_scroll,
66 } = self;
67
68 let mut pg = Page::new(
69 title,
70 info,
71 wgt_fn!(user_accepts, |_| {
72 let accept_enabled = var(required_scroll == 0.fct() || user_accepts.get());
73 Container! {
74 child_top = Text! {
75 margin = 10;
76 txt = if required_scroll >= 0.01.fct() {
77 l10n!(
78 "eula/message.requires_scroll",
79 "You must read and accept the terms of this agreement before continuing."
80 )
81 } else {
82 l10n!("eula/message", "You must accept the terms of this agreement before continuing.")
83 };
84 };
85 child = Scroll! {
86 padding = 10;
87 background_color = light_dark(rgb(0.87, 0.87, 0.87), rgb(0.13, 0.13, 0.13));
88 mode = license.map(|l| {
89 let mut mode = ScrollMode::VERTICAL;
90 if matches!(l, EulaTxt::PlainMono(_)) {
91 mode |= ScrollMode::HORIZONTAL;
93 }
94 mode
95 });
96 child = license.present(wgt_fn!(|l| match l {
97 EulaTxt::Plain(txt) => SelectableText! {
98 txt;
99 },
100 EulaTxt::PlainMono(txt) => SelectableText! {
101 txt;
102 font_family = "monospace";
103 txt_wrap = false;
104 },
105 EulaTxt::Markdown(txt) => Markdown! {
106 txt;
107 },
108 }));
109 on_init = hn!(accept_enabled, |_| {
110 if accept_enabled.get() {
111 return;
112 }
113 let offset = SCROLL.vertical_offset();
115 if offset.get() >= required_scroll {
116 accept_enabled.set(true);
117 } else {
118 let sub = offset.hook(clmv!(accept_enabled, |args| {
119 if *args.value() >= required_scroll {
120 accept_enabled.set(true);
121 return false;
122 }
123 true
124 }));
125 WIDGET.push_var_handle(sub);
126 }
127 });
128 };
129 child_bottom = Container! {
130 margin = 10;
131 child_spacing = 5;
132 toggle::selector = toggle::Selector::single(user_accepts.clone());
133 toggle::style_fn = toggle::RadioStyle!();
134 child_top = toggle::Toggle! {
135 child = Text!(l10n!("eula/accept.true", "I accept the agreement"));
136 enabled = accept_enabled;
137 value::<bool> = true;
138 };
139 child_bottom = toggle::Toggle! {
140 child = Text!(l10n!("eula/accept.false", "I do not accept the agreement"));
141 value::<bool> = false;
142 };
143 };
144 }
145 }),
146 );
147 pg.can_next.0 = user_accepts.read_only();
148 pg.content_fill = true;
149 pg
150 }
151}
152
153#[derive(Debug, PartialEq, Clone)]
155#[non_exhaustive]
156pub enum EulaTxt {
157 Plain(Txt),
159 PlainMono(Txt),
161 Markdown(Txt),
163}
164impl_from_and_into_var! {
165 fn from(plain: Txt) -> EulaTxt {
167 EulaTxt::Plain(plain)
168 }
169 fn from(plain: &'static str) -> EulaTxt {
171 EulaTxt::Plain(Txt::from_static(plain))
172 }
173
174 fn from(eula: EulaTxt) -> Txt {
175 match eula {
176 EulaTxt::Plain(txt) | EulaTxt::PlainMono(txt) | EulaTxt::Markdown(txt) => txt,
177 }
178 }
179}