diff --git a/packages/oneclient_app/src/components/icons.rs b/packages/oneclient_app/src/components/icons.rs index dd004183..182393e9 100644 --- a/packages/oneclient_app/src/components/icons.rs +++ b/packages/oneclient_app/src/components/icons.rs @@ -8,6 +8,7 @@ pub struct Icon { pub icon: IconType, pub size_px: f32, pub color: Option, + pub rotation: Option, } impl Icon { @@ -23,6 +24,7 @@ impl Icon { icon, size_px: 24., color, + rotation: None, } } @@ -35,6 +37,12 @@ impl Icon { self.color = Some(color); self } + + /// Rotation in degrees, clockwise. + pub fn rotate(mut self, degrees: f32) -> Self { + self.rotation = Some(degrees); + self + } } impl Component for Icon { @@ -48,6 +56,7 @@ impl Component for Icon { .height(Size::px(self.size_px)) // .fill(color) .map(self.color, |svg, color| svg.color(color)) + .map(self.rotation, |svg, degrees| svg.rotate(degrees)) } } diff --git a/packages/oneclient_app/src/view/app/settings/changelog.rs b/packages/oneclient_app/src/view/app/settings/changelog.rs index adc96f94..302c4af2 100644 --- a/packages/oneclient_app/src/view/app/settings/changelog.rs +++ b/packages/oneclient_app/src/view/app/settings/changelog.rs @@ -1,3 +1,6 @@ +use freya::animation::{ + AnimNum, Ease, Function, OnChange, OnCreation, use_animation_with_dependencies, +}; use freya::prelude::*; use super::settings_page; @@ -71,6 +74,10 @@ impl Component for SettingsChangelog { } } +/// Chevron angle for a collapsed card: `ChevronDown` swung a quarter turn +/// anticlockwise points right. +const CHEVRON_CLOSED_DEG: f32 = -90.; + #[derive(PartialEq)] struct ReleaseCard { version: String, @@ -84,6 +91,24 @@ impl Component for ReleaseCard { let mut open = use_state(|| self.initially_open); let is_open = *open.read(); + // One chevron that swings between pointing right (collapsed) and down + // (expanded), so the arrow tracks the section instead of cutting to a + // different glyph that did not follow the state. + let swing = use_animation_with_dependencies(&is_open, |conf, open| { + conf.on_creation(OnCreation::Run); + conf.on_change(OnChange::Rerun); + let (from, to) = if *open { + (CHEVRON_CLOSED_DEG, 0.) + } else { + (0., CHEVRON_CLOSED_DEG) + }; + AnimNum::new(from, to) + .time(180) + .ease(Ease::Out) + .function(Function::Cubic) + }); + let chevron_deg = swing.get().value(); + let title = if self.current { format!("{} (Currently Installed)", self.version) } else { @@ -122,14 +147,7 @@ impl Component for ReleaseCard { .font_weight(FontWeight::SEMI_BOLD) .color(colors::fg_primary()), ) - .child( - Icon::new(if is_open { - IconType::ChevronDown - } else { - IconType::ChevronRight - }) - .size(18.), - ), + .child(Icon::new(IconType::ChevronDown).size(18.).rotate(chevron_deg)), ) .maybe_child(is_open.then(|| { rect()