picking projects key nav and scrollable

tzemanovic
Feb 6, 2026, 3:07 PM
T4UECD3SERZLQMSESSATEHQEPFDIZGMMWY35EPV6JV2WOYMR7JRQC

Dependencies

  • [2] SASAN2XC use nav-scrollable
  • [3] LFEMJYYD start of to_record selection
  • [4] UTDTZCTX pull+push status, add info reports
  • [5] XQTT6NDF respect .ignore in file watch
  • [6] EIHMXSDR mv crate iced_expl_widget to inflorescence_iced_widget
  • [7] YRGDFHAB project dir picker
  • [8] LPSUBGUB add projects picker
  • [9] MORKDJUE use allowed actions binding for key subs
  • [10] 5BAPU7K6 dir picker key navigation
  • [11] CULHFNIV add error report view
  • [12] WAOGSCOJ very nice refactor, wip adding channels logs
  • [13] NWJD6VM6 mv libflowers libflorescence
  • [14] 2SLTGWP6 add change files diffs to-record selection
  • [15] 3XRG4BB6 rewritten nav-scrollable!
  • [16] 7WCB5YQJ refactor msgs and modules
  • [17] OPXFZKEB view tests setup
  • [18] AZ5D2LQU allow to set record description
  • [19] 23SFYK4Q big view refactor into a new crate
  • [20] AMPZ2BXK show changed files diffs (only Edit atm)
  • [*] EJPSD5XO shared allowed actions conditions between update and view
  • [*] 6YZAVBWU Initial commit

Change contents

  • replacement in inflorescence_view/src/view.rs at line 9
    [4.3418][7.18766:18839]()
    IndexSet, Job, Log, ManagingRepoSubState, ReadyState, RecordChanges,
    [4.3418]
    [4.3479]
    IndexSet, Job, Log, ManagingRepoSubState, PickingProjectSelection,
    ReadyState, RecordChanges,
  • edit in inflorescence_view/src/view.rs at line 90
    [8.13752]
    [8.13752]
    selection,
    projects_nav,
  • replacement in inflorescence_view/src/view.rs at line 98
    [8.13934][8.13934:13987]()
    .on_press(Msg::PickNewProject)),
    [8.13934]
    [8.13987]
    .on_press(Msg::PickNewProject)
    .class(
    if matches!(
    selection,
    PickingProjectSelection::FindOrCreate
    ) {
    theme::Button::Selected
    } else {
    theme::Button::Normal
    },
    )),
  • replacement in inflorescence_view/src/view.rs at line 113
    [8.14146][8.14146:14500]()
    el(column(projects.iter().map(
    |store::Project {
    last_closed_time: _,
    path,
    }| {
    el(button(text(format!("{}", path.to_string_lossy())))
    .on_press_with(|| Msg::OpenProject(path.clone())))
    },
    ))),
    [8.14146]
    [8.14500]
    el(nav_scrollable(
    projects_nav,
    projects.iter().enumerate().map(
    |(ix, store::Project {
    last_closed_time: _,
    path,
    })| {
    el(button(text(format!("{}", path.to_string_lossy())))
    .on_press_with(|| Msg::OpenProject(path.clone()))
    .class(
    if matches!(
    selection,
    PickingProjectSelection::Existing { ix: selection } if *selection == ix
    ) {
    theme::Button::Selected
    } else {
    theme::Button::Normal
    },
    )
    )
    },
    ),
    ).class(if matches!(selection, PickingProjectSelection::Existing { .. }) {
    theme::Scrollable::Selected
    } else {
    theme::Scrollable::Normal
    }).width(Length::Fill).height(Length::Fill)),
  • edit in inflorescence_model/src/model.rs at line 51
    [8.15137]
    [8.15137]
    pub selection: PickingProjectSelection,
    pub projects_nav: nav_scrollable::State,
  • edit in inflorescence_model/src/model.rs at line 55
    [8.15140]
    [8.15140]
    #[derive(Debug, Clone, Copy, Default)]
    pub enum PickingProjectSelection {
    #[default]
    FindOrCreate,
    Existing {
    ix: usize,
    },
    }
  • edit in inflorescence_model/src/action.rs at line 249
    [10.1658][10.1658:1682]()
    is_blocking: _,
  • edit in inflorescence_model/src/action.rs at line 250
    [10.1700]
    [10.1700]
    is_blocking: _,
    selection: _,
    projects_nav: _,
  • edit in inflorescence_model/src/action.rs at line 254
    [10.1715]
    [10.1715]
    let mut actions = vec![];
    let ma = &mut actions;
  • replacement in inflorescence_model/src/action.rs at line 259
    [10.1744][10.1744:1799]()
    vec![down(), up()]
    } else {
    vec![]
    [10.1744]
    [9.171877]
    push(|| confirm("Confirm selection"), ma);
    push(down, ma);
    push(up, ma);
  • edit in inflorescence_model/src/action.rs at line 263
    [9.171883]
    [9.171883]
    actions
  • replacement in inflorescence/src/main.rs at line 11
    [5.372][7.3609296:3609349](),[5.372][4.6637:6714](),[6.937][4.6637:6714](),[7.3609349][4.6637:6714](),[2.2366][4.6637:6714]()
    use inflorescence_iced_widget::{dir_picker, report};
    use inflorescence_model::model::{Job, Log, Logs, ReadyState, RecordChanges};
    [5.372]
    [3.16818]
    use inflorescence_iced_widget::{dir_picker, nav_scrollable, report};
    use inflorescence_model::model::{
    Job, Log, Logs, PickingProjectSelection, ReadyState, RecordChanges,
    };
  • edit in inflorescence/src/main.rs at line 189
    [8.16965]
    [8.16965]
    selection: default(),
    projects_nav: nav_scrollable::State::default(),
  • replacement in inflorescence/src/main.rs at line 367
    [8.20496][8.20496:20536]()
    _model: &mut model::PickingProject,
    [8.20496]
    [8.20536]
    model: &mut model::PickingProject,
  • replacement in inflorescence/src/main.rs at line 373
    [8.20717][8.20717:20761]()
    view::Msg::Action(_msg) => todo!(),
    [8.20717]
    [8.20761]
    view::Msg::Action(msg) => match msg {
    action::FilteredMsg::Confirm => match model.selection {
    PickingProjectSelection::FindOrCreate => {
    let (model, task) = init_picking_repo_dir();
    new_state = Some(model::SubState::PickingRepoDir(model));
    task
    }
    PickingProjectSelection::Existing { ix } => {
    if let Some(store::Project {
    last_closed_time: _,
    path,
    }) = model
    .projects
    .as_ref()
    .and_then(|projects| projects.iter().nth(ix))
    {
    let (sub, managing_repo, managing_repo_task) =
    init_managing_repo(path.clone());
    new_state = Some(model::SubState::ManagingRepo(sub));
    new_managing_repo = Some(managing_repo);
    managing_repo_task
    } else {
    Task::none()
    }
    }
    },
    action::FilteredMsg::Selection(msg) => {
    picking_project_selection(model, msg)
    }
    action::FilteredMsg::Cancel
    | action::FilteredMsg::PostponeRecord
    | action::FilteredMsg::SaveRecord
    | action::FilteredMsg::DiscardRecord
    | action::FilteredMsg::AddUntrackedFile
    | action::FilteredMsg::RmChange
    | action::FilteredMsg::StartRecord
    | action::FilteredMsg::SelectChannel
    | action::FilteredMsg::ForkChannel
    | action::FilteredMsg::RefreshRepo
    | action::FilteredMsg::ShowEntireLog
    | action::FilteredMsg::FocusNext
    | action::FilteredMsg::FocusPrev
    | action::FilteredMsg::ClipboardCopy
    | action::FilteredMsg::ToggleReports
    | action::FilteredMsg::ClipboardCopyReports
    | action::FilteredMsg::ToRecord(_)
    | action::FilteredMsg::ToRecordToggleSelectedFileOrChange
    | action::FilteredMsg::EnterSubMenu(_) => Task::none(),
    },
  • edit in inflorescence/src/main.rs at line 442
    [8.21555]
    [8.21555]
    }
    fn picking_project_selection(
    model: &mut model::PickingProject,
    msg: inflorescence_model::selection::Msg,
    ) -> Task<Msg> {
    match msg {
    selection::Msg::PressDir(dir) => {
    if let Some(projects) = model.projects.as_mut()
    && !projects.is_empty()
    {
    match model.selection {
    PickingProjectSelection::FindOrCreate => match dir {
    selection::Dir::Down => {
    model.selection =
    PickingProjectSelection::Existing { ix: 0 };
    }
    selection::Dir::Up => {
    model.selection =
    PickingProjectSelection::Existing {
    ix: projects.len() - 1,
    };
    }
    selection::Dir::Right | selection::Dir::Left => {}
    },
    PickingProjectSelection::Existing { ix } => match dir {
    selection::Dir::Down => {
    if ix < projects.len() - 1 {
    let ix = ix + 1;
    model.selection =
    PickingProjectSelection::Existing { ix };
    nav_scrollable::scroll_down_to_section(
    &mut model.projects_nav,
    ix,
    );
    } else {
    model.selection =
    PickingProjectSelection::FindOrCreate;
    nav_scrollable::scroll_up_to_section(
    &mut model.projects_nav,
    0,
    );
    }
    }
    selection::Dir::Up => {
    if ix > 0 {
    let ix = ix - 1;
    model.selection =
    PickingProjectSelection::Existing { ix };
    nav_scrollable::scroll_up_to_section(
    &mut model.projects_nav,
    ix,
    );
    } else {
    model.selection =
    PickingProjectSelection::FindOrCreate;
    nav_scrollable::scroll_up_to_section(
    &mut model.projects_nav,
    0,
    );
    }
    }
    selection::Dir::Right | selection::Dir::Left => {}
    },
    }
    }
    Task::none()
    }
    selection::Msg::AltPressDir(_) => Task::none(),
    }