Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions crates/linkunbound-core/src/i18n.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,6 @@ catalogue! {
picker_preview: "Vista previa: elegir no abre nada" | "Preview: choosing opens nothing",
picker_add: "Añadir navegador" | "Add a browser",
picker_add_more: "o un perfil" | "or a profile",
styles_headline: "El selector ahora es el oso" | "The picker is now the bear",
styles_reason: "¿Prefieres otro estilo? Elígelo aquí o en Ajustes" | "Prefer another look? Pick it here or in Settings",
style_classic: "Clásico" | "Classic",
style_sheet: "Mosaico" | "Tiles",
style_compact: "Compacto" | "Compact",
style_bear: "Oso" | "Bear",
browser_copy_suffix: "{} (copia)" | "{} (copy)",
reach_once: "Solo esta vez" | "Just this time",
reach_url: "Esta URL" | "This URL",
Expand Down
6 changes: 3 additions & 3 deletions crates/linkunbound-shell/src/mascot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ struct Pose {

const BEAR: Pose = Pose {
head: 92.0,
rise: 62.0,
rise: 52.0,
paw: 30.0,
gap: 70.0,
};
Expand Down Expand Up @@ -268,13 +268,13 @@ mod tests {
#[test]
fn the_bear_leans_on_the_middle_of_the_sheet() {
let (head, paws) = spots(&BEAR, (100, 300), 400.0, 0.0, 1.0);
assert_eq!(head, (300 - 46, 300 - 62));
assert_eq!(head, (300 - 46, 300 - 52));
assert_eq!(paws, (300 - 65, 300 - 9));

let (head, _) = spots(&BEAR, (200, 600), 400.0, 18.0, 2.0);
assert_eq!(
head,
(600 - 92, 636 - 124),
(600 - 92, 636 - 104),
"pixels on a dense screen, under a shadow margin"
);
}
Expand Down
127 changes: 35 additions & 92 deletions crates/linkunbound-shell/src/notice.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::rc::Rc;
use std::time::Duration;

use linkunbound_core::{PickerStyle, Strings};
use linkunbound_core::Strings;
use linkunbound_shell::Notice;
use slint::ComponentHandle;

Expand All @@ -16,7 +15,6 @@
notice.set_reason(reason.into());
notice.set_undo_label(undo.unwrap_or_default().into());
notice.set_undoable(undo.is_some());
notice.set_choices(slint::ModelRc::default());
notice.set_left(NOTICE_SECONDS);
let _ = notice.show();
if let Some(handle) = native_handle(notice.window()) {
Expand All @@ -30,75 +28,22 @@
}
}

/// The looks the notice offers, in the order it draws them: the bear first, as the one in use.
const OFFERED: [PickerStyle; 4] = [
PickerStyle::Bear,
PickerStyle::Classic,
PickerStyle::Sheet,
PickerStyle::Compact,
];
const STYLES_SECONDS: i32 = 20;

/// Once, after the update moved everybody to the bear: whatever look they had stays one press
/// away, in the corner, instead of three windows deep in settings.
/// Once, after the update: everybody moves to the bear. Settings opens on its own to tell what
/// the version brings, and the look can be changed there.
pub fn after_the_bear(state: &Rc<Ui>) {
let mut left_behind = None;
let _ = store().edit_prefs(|prefs| {
let before = prefs.schema_version;
left_behind = prefs.meets_the_bear();
prefs.schema_version != before
});
if left_behind.is_none() {
return;
if moved_to_the_bear(&store()) {
state.obey(&store().prefs());
}

Check warning on line 36 in crates/linkunbound-shell/src/notice.rs

View workflow job for this annotation

GitHub Actions / crates / the lines this branch changed

Missed mutant

replace after_the_bear with ()

Check warning on line 36 in crates/linkunbound-shell/src/notice.rs

View workflow job for this annotation

GitHub Actions / mac / the lines this branch changed

Missed mutant

replace after_the_bear with ()
state.obey(&store().prefs());
state.notice.on_chose(|at| {
let Some(ui) = ui() else { return };
let chosen = OFFERED[usize::try_from(at).unwrap_or(0).min(OFFERED.len() - 1)];
let _ = store().edit_prefs(|prefs| {
prefs.picker_style = chosen;
true
});
ui.obey(&store().prefs());
ui.countdown.stop();
let _ = ui.notice.hide();
});
// Shown from inside the loop: before it runs the window has no handle to keep it off the
// taskbar.
slint::Timer::single_shot(Duration::ZERO, || {
if let Some(ui) = ui() {
offer_styles(&ui);
}
});
}

fn offer_styles(ui: &Rc<Ui>) {
{
let words = ui.words.get();
flash(
&ui.notice,
words.styles_headline.to_owned(),
words.styles_reason.to_owned(),
None,
);
let names: Vec<slint::SharedString> = OFFERED
.iter()
.map(|style| {
match style {
PickerStyle::Bear => words.style_bear,
PickerStyle::Classic => words.style_classic,
PickerStyle::Sheet => words.style_sheet,
PickerStyle::Compact => words.style_compact,
}
.into()
})
.collect();
ui.notice
.set_choices(Rc::new(slint::VecModel::from(names)).into());
ui.notice.set_left(STYLES_SECONDS);
in_the_corner(&ui.notice);
ui.count_down();
}
fn moved_to_the_bear(store: &linkunbound_core::Store) -> bool {
let mut moved = false;
let _ = store.edit_prefs(|prefs| {
let before = prefs.schema_version;
moved = prefs.meets_the_bear().is_some();
prefs.schema_version != before
});
moved
}

pub fn noted(area: &'static str, what: &str) {
Expand Down Expand Up @@ -149,34 +94,32 @@

#[cfg(test)]
mod tests {
use super::{OFFERED, STYLES_SECONDS, flash, offer_styles};
use slint::Model;
use super::{flash, moved_to_the_bear};
use linkunbound_core::{PickerStyle, Store};
use linkunbound_shell::Notice;

/// The look in use comes first and every other one is a press away, for longer than a notice
/// about a rule stays.
/// A look chosen before the update moves to the bear once, and is left alone after that.
#[test]
fn the_looks_are_offered_with_the_bear_first() {
let ui = crate::tests::headless_ui();
offer_styles(&ui);
let choices = ui.notice.get_choices();
assert_eq!(choices.row_count(), OFFERED.len());
assert_eq!(choices.row_data(0).as_deref(), Some("Bear"));
assert_eq!(ui.notice.get_left(), STYLES_SECONDS);
assert!(!ui.notice.get_undoable());
fn the_bear_is_met_once() {
let dir = std::env::temp_dir().join(format!("linkunbound-bear-{}", std::process::id()));
let _ = std::fs::remove_dir_all(&dir);
let store = Store::at(&dir);
let _ = store.edit_prefs(|prefs| {
prefs.picker_style = PickerStyle::Sheet;
prefs.schema_version = 0;
true
});
assert!(moved_to_the_bear(&store));
assert_eq!(store.prefs().picker_style, PickerStyle::Bear);

flash(
&ui.notice,
"Opened".into(),
"by a rule".into(),
Some("Undo"),
);
assert_eq!(
ui.notice.get_choices().row_count(),
0,
"a later notice offers no looks"
);
let _ = store.edit_prefs(|prefs| {
prefs.picker_style = PickerStyle::Compact;
true
});
assert!(!moved_to_the_bear(&store), "once is enough");
assert_eq!(store.prefs().picker_style, PickerStyle::Compact);
let _ = std::fs::remove_dir_all(&dir);
}
use linkunbound_shell::Notice;

#[test]
fn a_notice_about_trouble_offers_nothing_to_undo() {
Expand Down
33 changes: 1 addition & 32 deletions crates/linkunbound-shell/ui/shell.slint
Original file line number Diff line number Diff line change
Expand Up @@ -398,10 +398,6 @@ export component Notice inherits Window {
in property <string> undo-label;
in property <bool> undoable: true;
in-out property <int> left: 6;
// Looks offered once after the update made the bear everybody's, the current one first.
in property <[string]> choices;
callback chose(int);

callback undo();
callback dismissed();

Expand All @@ -410,7 +406,7 @@ export component Notice inherits Window {
no-frame: true;
background: transparent;
out property <length> wanted-width: 356px;
out property <length> wanted-height: root.choices.length > 0 ? 120px : 76px;
out property <length> wanted-height: 76px;
width: root.wanted-width;
height: root.wanted-height;
in property <string> family;
Expand Down Expand Up @@ -487,33 +483,6 @@ export component Notice inherits Window {
}
}
}
if root.choices.length > 0: HorizontalLayout {
height: 44px;
padding-left: 12px;
padding-right: 12px;
padding-bottom: 12px;
spacing: 6px;
for choice[i] in root.choices: Rectangle {
horizontal-stretch: 1;
border-radius: 6px;
background: i == 0 ? Palette.brand-soft : (pick.has-hover ? Palette.hover : Palette.chip);
border-width: i == 0 ? 1px : 0px;
border-color: Palette.brand;
Text {
text: choice;
font-size: 12.5px;
font-weight: i == 0 ? 600 : 400;
color: i == 0 ? Palette.brand : Palette.ink;
horizontal-alignment: center;
vertical-alignment: center;
width: 100%;
height: 100%;
}
pick := TouchArea {
clicked => { root.chose(i); }
}
}
}
}
}
}
Loading