🏡 index : ~doyle/shalom.git

author Jordan Doyle <jordan@doyle.la> 2024-01-13 19:02:35.0 +00:00:00
committer Jordan Doyle <jordan@doyle.la> 2024-01-13 19:02:35.0 +00:00:00
commit
7b288167d76fcb7fe1be5c00b15eab388e88e086 [patch]
tree
02901cead01e9dd177f98d3f9adb2ce1a75fa57a
parent
81f06af5732d7cf72e0c8c25451872c7bfc8e9aa
download
7b288167d76fcb7fe1be5c00b15eab388e88e086.tar.gz

Scroll to top before closing search bar



Diff

 Cargo.lock                        |  1 +-
 iced                              |  2 +-
 shalom/src/magic/header_search.rs | 75 ++++++++++++++++++++++++----------------
 shalom/src/pages/room.rs          | 30 ++++++++++++++--
 shalom/src/pages/room/listen.rs   |  8 ++--
 5 files changed, 79 insertions(+), 37 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 4a57cfa..16ababb 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1394,6 +1394,7 @@ dependencies = [
 "iced_renderer",
 "iced_runtime",
 "iced_style",
 "keyframe",
 "num-traits",
 "ouroboros",
 "thiserror",
diff --git a/iced b/iced
index c30197d..f8a73b7 160000
--- a/iced
+++ b/iced
@@ -1 +1 @@
Subproject commit c30197d3c7e46dde933f6839662023222f07d30a
Subproject commit f8a73b7de909d72a90f9908b61fbdde88e0debcb
diff --git a/shalom/src/magic/header_search.rs b/shalom/src/magic/header_search.rs
index d0aae8d..094dede 100644
--- a/shalom/src/magic/header_search.rs
+++ b/shalom/src/magic/header_search.rs
@@ -27,7 +27,7 @@ const INITIAL_SEARCH_BOX_SIZE: Size = Size::new(78., 78.);

pub fn header_search<'a, M>(
    on_input: fn(String) -> M,
    on_state_change: fn(bool) -> M,
    open_state_toggle: M,
    open: bool,
    search_query: &str,
    mut header: Text<'a, Renderer>,
@@ -49,12 +49,13 @@ where
        original_header: header.clone(),
        header,
        current_search_box_size,
        open,
        open_state_toggle,
        input: iced::widget::text_input("Search...", search_query)
            .id(Id::unique())
            .on_input(on_input)
            .style(iced::theme::TextInput::Custom(Box::new(InputStyle)))
            .into(),
        on_state_change,
        search_icon: Element::from(Icon::Search.canvas(Color::BLACK)),
        close_icon: Element::from(Icon::Close.canvas(Color::BLACK)),
        dy_mult,
@@ -72,11 +73,12 @@ pub struct HeaderSearch<'a, M> {
    original_header: Text<'a, Renderer>,
    header: Text<'a, Renderer>,
    current_search_box_size: BoxSize,
    on_state_change: fn(bool) -> M,
    input: Element<'a, M, Renderer>,
    search_icon: Element<'a, M, Renderer>,
    close_icon: Element<'a, M, Renderer>,
    dy_mult: f32,
    open: bool,
    open_state_toggle: M,
}

impl<'a, M> Widget<M, Renderer> for HeaderSearch<'a, M>
@@ -219,9 +221,10 @@ where
        }
    }

    #[allow(clippy::too_many_lines)]
    fn on_event(
        &mut self,
        state: &mut Tree,
        tree_state: &mut Tree,
        event: iced::Event,
        layout: Layout<'_>,
        cursor: Cursor,
@@ -230,6 +233,20 @@ where
        shell: &mut Shell<'_, M>,
        viewport: &Rectangle,
    ) -> Status {
        let state = tree_state.state.downcast_mut::<State>();

        match state {
            State::Open if !self.open => {
                *state = State::close();
                shell.request_redraw(RedrawRequest::NextFrame);
            }
            State::Closed if self.open => {
                *state = State::open();
                shell.request_redraw(RedrawRequest::NextFrame);
            }
            _ => {}
        }

        let status = match event {
            iced::Event::Mouse(iced::mouse::Event::ButtonPressed(mouse::Button::Left))
            | iced::Event::Touch(iced::touch::Event::FingerPressed { .. })
@@ -244,13 +261,13 @@ where
                        .bounds(),
                ) =>
            {
                let state = state.state.downcast_mut::<State>();
                *state = state.clone().flip();
                shell.request_redraw(RedrawRequest::NextFrame);
                if !matches!(state, State::Animate { .. }) {
                    shell.publish(self.open_state_toggle.clone());
                }

                Status::Captured
            }
            iced::Event::Window(iced::window::Event::RedrawRequested(_)) => {
                let state = state.state.downcast_mut::<State>();
                let State::Animate {
                    last_draw,
                    next_state,
@@ -301,11 +318,9 @@ where

                    match &state {
                        State::Open => {
                            shell.publish((self.on_state_change)(true));
                            self.current_search_box_size = BoxSize::Fill;
                        }
                        State::Closed => {
                            shell.publish((self.on_state_change)(false));
                            self.current_search_box_size = BoxSize::Min;
                        }
                        State::Animate { .. } => {}
@@ -321,7 +336,7 @@ where

        if status == Status::Ignored {
            self.input.as_widget_mut().on_event(
                &mut state.children[0],
                &mut tree_state.children[0],
                event,
                layout.children().nth(1).unwrap().children().nth(1).unwrap(),
                cursor,
@@ -396,25 +411,25 @@ pub enum State {
}

impl State {
    fn flip(self) -> Self {
        match self {
            State::Closed => Self::Animate {
                last_draw: Instant::now(),
                next_state: Box::new(State::Open),
                text_opacity: keyframes![(1.0, 0.0, EaseOutQuint), (0.0, 0.5)],
                search_box_size: keyframes![(0.0, 0.0, EaseOutQuint), (0.0, 0.1), (1.0, 0.5)],
                search_icon: keyframes![(1.0, 0.0, EaseOutQuint), (0.0, 0.5)],
                close_icon: keyframes![(0.0, 0.0, EaseOutQuint), (0.0, 0.1), (1.0, 0.5)],
            },
            State::Open => Self::Animate {
                last_draw: Instant::now(),
                next_state: Box::new(State::Closed),
                text_opacity: keyframes![(0.0, 0.0, EaseOutQuint), (0.0, 0.1), (1.0, 0.5)],
                search_box_size: keyframes![(1.0, 0.0, EaseOutQuint), (0.0, 0.5)],
                search_icon: keyframes![(0.0, 0.0, EaseOutQuint), (0.0, 0.1), (1.0, 0.5)],
                close_icon: keyframes![(1.0, 0.0, EaseOutQuint), (0.0, 0.5)],
            },
            v @ State::Animate { .. } => v,
    fn open() -> Self {
        Self::Animate {
            last_draw: Instant::now(),
            next_state: Box::new(State::Open),
            text_opacity: keyframes![(1.0, 0.0, EaseOutQuint), (0.0, 0.5)],
            search_box_size: keyframes![(0.0, 0.0, EaseOutQuint), (0.0, 0.1), (1.0, 0.5)],
            search_icon: keyframes![(1.0, 0.0, EaseOutQuint), (0.0, 0.5)],
            close_icon: keyframes![(0.0, 0.0, EaseOutQuint), (0.0, 0.1), (1.0, 0.5)],
        }
    }

    fn close() -> Self {
        Self::Animate {
            last_draw: Instant::now(),
            next_state: Box::new(State::Closed),
            text_opacity: keyframes![(0.0, 0.0, EaseOutQuint), (0.0, 0.1), (1.0, 0.5)],
            search_box_size: keyframes![(1.0, 0.0, EaseOutQuint), (0.0, 0.5)],
            search_icon: keyframes![(0.0, 0.0, EaseOutQuint), (0.0, 0.1), (1.0, 0.5)],
            close_icon: keyframes![(1.0, 0.0, EaseOutQuint), (0.0, 0.5)],
        }
    }
}
diff --git a/shalom/src/pages/room.rs b/shalom/src/pages/room.rs
index 71389c3..f80add8 100644
--- a/shalom/src/pages/room.rs
+++ b/shalom/src/pages/room.rs
@@ -36,6 +36,7 @@ pub struct Room {
    listen: listen::Listen,
    current_page: Page,
    dy: f32,
    pending_visible_toggle: bool,
}

impl Room {
@@ -49,6 +50,7 @@ impl Room {
            room,
            current_page: Page::Listen,
            dy: 0.0,
            pending_visible_toggle: false,
        }
    }

@@ -59,16 +61,38 @@ impl Room {
    pub fn update(&mut self, event: Message) -> Option<Event> {
        match event {
            Message::Lights(v) => self.lights.update(v).map(Event::Lights),
            Message::Listen(listen::Message::OnSearchVisibleToggle)
                if self.listen.search.is_open() && self.dy > 0.0 =>
            {
                // intercept search toggles on listen so we can scroll our scrollable to
                // the top first
                self.pending_visible_toggle = true;
                None
            }
            Message::Listen(v) => self.listen.update(v).map(Event::Listen),
            Message::ChangePage(page) => {
                self.dy = 0.0;
                self.current_page = page;
                None
            }
            Message::Exit => Some(Event::Exit),
            Message::Exit => {
                self.dy = 0.0;
                Some(Event::Exit)
            }
            Message::OnContentScroll(viewport) => {
                self.dy = viewport.absolute_offset().y;
                None
            }
            Message::OnContentAnimateFinished => {
                if self.pending_visible_toggle {
                    self.pending_visible_toggle = false;
                    self.listen
                        .update(listen::Message::OnSearchVisibleToggle)
                        .map(Event::Listen)
                } else {
                    None
                }
            }
        }
    }

@@ -120,7 +144,6 @@ impl Room {
            .spacing(20.0 * (1.0 - padding_mult))
            .push(header);

        // TODO: on close, we need to animate the scrollback by padding the container up to dy
        if needs_scrollable {
            current = scrollable(container(current).width(Length::Fill).padding([
                f32::from(PADDING + 30) * padding_mult,
@@ -132,6 +155,8 @@ impl Room {
                Properties::default().scroller_width(0).width(0),
            ))
            .on_scroll(Message::OnContentScroll)
            .on_animate_finished(Message::OnContentAnimateFinished)
            .scroll_to_top(self.pending_visible_toggle)
            .into();
        }

@@ -183,5 +208,6 @@ pub enum Message {
    Listen(listen::Message),
    ChangePage(Page),
    OnContentScroll(Viewport),
    OnContentAnimateFinished,
    Exit,
}
diff --git a/shalom/src/pages/room/listen.rs b/shalom/src/pages/room/listen.rs
index 44016f0..0d3df6e 100644
--- a/shalom/src/pages/room/listen.rs
+++ b/shalom/src/pages/room/listen.rs
@@ -69,7 +69,7 @@ impl Listen {

                header_search(
                    Message::OnSearchTerm,
                    Message::OnSearchVisibleChange,
                    Message::OnSearchVisibleToggle,
                    open,
                    query,
                    text.clone(),
@@ -180,8 +180,8 @@ impl Listen {
                self.search = self.search.open(v);
                None
            }
            Message::OnSearchVisibleChange(v) => {
                self.search = if v {
            Message::OnSearchVisibleToggle => {
                self.search = if matches!(self.search, SearchState::Closed) {
                    SearchState::Open {
                        search: String::new(),
                        results_search: String::new(),
@@ -421,7 +421,7 @@ pub enum Message {
    OnSpeakerNextTrack,
    OnSpeakerPreviousTrack,
    OnSearchTerm(String),
    OnSearchVisibleChange(bool),
    OnSearchVisibleToggle,
    SpotifySearchResult((SearchResult, String)),
    SpotifySearchResultError((String, String)),
    OnPlayTrack(String),