add cursor with selection

[?]
Feb 8, 2025, 8:11 PM
WT3GA27PQ2AOAIGK65O3Q4DMX4AZDVNULBLRL6GF4QW6QCASUEAAC

Dependencies

Change contents

  • edit in crates/libflowers_client/src/lib.rs at line 1
    [2.1360]
    [6.4785]
    pub mod cursor;
  • file addition: cursor.rs (----------)
    [5.36]
    #[derive(Debug, Default)]
    pub struct State {
    pub selection: Option<Selection>,
    }
    #[derive(Debug, Clone)]
    pub enum Selection {
    Channel,
    File(usize),
    }
  • edit in crates/libflowers/src/prelude.rs at line 8
    [4.602]
    [4.602]
    #[inline]
    pub fn default<T: Default>() -> T {
    Default::default()
    }
  • edit in crates/flowers_ui/src/main.rs at line 1
    [2.2763]
    [4.1000]
    use std::io::Cursor;
  • replacement in crates/flowers_ui/src/main.rs at line 5
    [6.4842][6.4842:4871]()
    use libflowers_client::repo;
    [6.4842]
    [4.1024]
    use libflowers_client::{cursor, repo};
  • replacement in crates/flowers_ui/src/main.rs at line 7
    [4.1025][6.4872:4970]()
    use iced::widget::{column, horizontal_rule, row, text};
    use iced::{Element, Length, Task, Theme};
    [4.1025]
    [2.2834]
    use iced::widget::{button, column, horizontal_rule, row, text};
    use iced::{Border, Color, Element, Length, Subscription, Task, Theme};
  • edit in crates/flowers_ui/src/main.rs at line 12
    [3.5905]
    [2.2922]
    .subscription(subs)
  • replacement in crates/flowers_ui/src/main.rs at line 21
    [6.5041][6.5041:5076]()
    (State { repo }, Task::none())
    [6.5041]
    [4.1328]
    let cursor = cursor::State::default();
    (State { repo, cursor }, Task::none())
  • edit in crates/flowers_ui/src/main.rs at line 28
    [6.5100]
    [4.1403]
    cursor: cursor::State,
  • replacement in crates/flowers_ui/src/main.rs at line 36
    [2.3066][6.5101:5117]()
    enum Message {}
    [2.3066]
    [2.3098]
    enum Message {
    CursorDown,
    CursorUp,
    CursorSelect(cursor::Selection),
    }
  • replacement in crates/flowers_ui/src/main.rs at line 43
    [4.1455][6.5118:5139]()
    match message {}
    [4.1455]
    [2.3221]
    match message {
    Message::CursorDown => {
    state.cursor.selection =
    Some(match state.cursor.selection.as_ref() {
    Some(cursor::Selection::Channel) => {
    if state.repo.changed_files.is_empty() {
    cursor::Selection::Channel
    } else {
    cursor::Selection::File(0)
    }
    }
    Some(cursor::Selection::File(ix)) => {
    if state.repo.changed_files.len().saturating_sub(1)
    == *ix
    {
    cursor::Selection::Channel
    } else {
    cursor::Selection::File(ix + 1)
    }
    }
    None => cursor::Selection::Channel,
    })
    }
    Message::CursorUp => {
    state.cursor.selection =
    Some(match state.cursor.selection.as_ref() {
    Some(cursor::Selection::Channel) | None => {
    if state.repo.changed_files.is_empty() {
    cursor::Selection::Channel
    } else {
    cursor::Selection::File(
    state.repo.changed_files.len() - 1,
    )
    }
    }
    Some(cursor::Selection::File(ix)) => {
    if 0 == *ix {
    cursor::Selection::Channel
    } else {
    cursor::Selection::File(ix - 1)
    }
    }
    })
    }
    Message::CursorSelect(selection) => {
    state.cursor.selection = Some(selection)
    }
    }
    }
    fn subs(_state: &State) -> Subscription<Message> {
    use iced::keyboard::{on_key_press, Key};
    on_key_press(|key, mods| {
    if mods.is_empty() {
    match key {
    Key::Character(c) => match c.as_str() {
    "j" => Some(Message::CursorDown),
    "k" => Some(Message::CursorUp),
    _ => None,
    },
    Key::Named(_) | Key::Unidentified => None,
    }
    } else {
    None
    }
    })
  • edit in crates/flowers_ui/src/main.rs at line 115
    [6.5242]
    [6.5242]
    let is_channel_selected = matches!(
    state.cursor.selection.as_ref(),
    Some(cursor::Selection::Channel)
    );
  • replacement in crates/flowers_ui/src/main.rs at line 122
    [6.5356][6.5356:5394]()
    Element::from(text(channel)),
    [6.5356]
    [6.5394]
    Element::from(
    button(text(channel))
    .on_press(Message::CursorSelect(cursor::Selection::Channel))
    .style(selectable_button_style(is_channel_selected)),
    ),
  • replacement in crates/flowers_ui/src/main.rs at line 128
    [6.5403][6.5403:5588]()
    let changed_files = Element::from(column(
    state
    .repo
    .changed_files
    .iter()
    .map(|path| Element::from(text(path))),
    ));
    [6.5403]
    [6.5588]
    let changed_files =
    Element::from(column(state.repo.changed_files.iter().enumerate().map(
    |(ix, path)| {
    let is_selected = matches!(state.cursor.selection.as_ref() ,
    Some(cursor::Selection::File(selected_ix)) if &ix == selected_ix
    );
    Element::from(
    button(text(path))
    .on_press(Message::CursorSelect(
    cursor::Selection::File(ix),
    ))
    .style(selectable_button_style(is_selected)),
    )
    },
    )));
  • edit in crates/flowers_ui/src/main.rs at line 150
    [6.5731]
    [6.5731]
  • edit in crates/flowers_ui/src/main.rs at line 164
    [6.6123]
    [2.3333]
    }
    fn selectable_button_style(
    is_selected: bool,
    ) -> impl Fn(&Theme, button::Status) -> button::Style {
    move |theme, status| -> button::Style {
    button::Style {
    border: Border {
    color: if is_selected {
    Color::WHITE
    } else {
    Color::TRANSPARENT
    },
    width: 1.0,
    ..default()
    },
    ..button::Catalog::style(
    theme,
    &<Theme as button::Catalog>::default(),
    status,
    )
    }
    }