diff --git a/crates/linkunbound-core/src/i18n.rs b/crates/linkunbound-core/src/i18n.rs index 128deb8..fc04d7e 100644 --- a/crates/linkunbound-core/src/i18n.rs +++ b/crates/linkunbound-core/src/i18n.rs @@ -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", diff --git a/crates/linkunbound-shell/src/mascot.rs b/crates/linkunbound-shell/src/mascot.rs index 44543b5..e63306c 100644 --- a/crates/linkunbound-shell/src/mascot.rs +++ b/crates/linkunbound-shell/src/mascot.rs @@ -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, }; @@ -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" ); } diff --git a/crates/linkunbound-shell/src/notice.rs b/crates/linkunbound-shell/src/notice.rs index c28fe82..2b5d553 100644 --- a/crates/linkunbound-shell/src/notice.rs +++ b/crates/linkunbound-shell/src/notice.rs @@ -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; @@ -16,7 +15,6 @@ pub fn flash(notice: &Notice, headline: String, reason: String, undo: Option<&st 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()) { @@ -30,75 +28,22 @@ pub fn flash(notice: &Notice, headline: String, reason: String, undo: Option<&st } } -/// 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) { - 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()); } - 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) { - { - let words = ui.words.get(); - flash( - &ui.notice, - words.styles_headline.to_owned(), - words.styles_reason.to_owned(), - None, - ); - let names: Vec = 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) { @@ -149,34 +94,32 @@ fn in_the_corner(notice: &Notice) { #[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() { diff --git a/crates/linkunbound-shell/ui/shell.slint b/crates/linkunbound-shell/ui/shell.slint index d86926f..704ede6 100644 --- a/crates/linkunbound-shell/ui/shell.slint +++ b/crates/linkunbound-shell/ui/shell.slint @@ -398,10 +398,6 @@ export component Notice inherits Window { in property undo-label; in property undoable: true; in-out property 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(); @@ -410,7 +406,7 @@ export component Notice inherits Window { no-frame: true; background: transparent; out property wanted-width: 356px; - out property wanted-height: root.choices.length > 0 ? 120px : 76px; + out property wanted-height: 76px; width: root.wanted-width; height: root.wanted-height; in property family; @@ -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); } - } - } - } } } }