Skip to main content

things3_cloud/ui/views/
find.rs

1use crate::common::ICONS;
2use crate::store::{Task, ThingsStore};
3use crate::ui::components::empty_text::EmptyText;
4use crate::ui::components::project_item::ProjectItem;
5use crate::ui::components::task_item::TaskItem;
6use crate::ui::components::tasks::TaskOptions;
7use iocraft::prelude::*;
8use std::sync::Arc;
9
10#[derive(Clone)]
11pub struct FindRow<'a> {
12    pub task: &'a Task,
13    pub force_detailed: bool,
14}
15
16#[derive(Default, Props)]
17pub struct FindViewProps<'a> {
18    pub rows: Vec<FindRow<'a>>,
19    pub detailed: bool,
20}
21
22#[component]
23pub fn FindView<'a>(hooks: Hooks, props: &FindViewProps<'a>) -> impl Into<AnyElement<'a>> {
24    let store = hooks.use_context::<Arc<ThingsStore>>().clone();
25
26    if props.rows.is_empty() {
27        return element! { EmptyText(content: "No matching tasks.") }.into_any();
28    }
29
30    let id_prefix_len = store.unique_prefix_length(
31        &props
32            .rows
33            .iter()
34            .map(|row| row.task.uuid.clone())
35            .collect::<Vec<_>>(),
36    );
37
38    let count = props.rows.len();
39    let label = if count == 1 { "task" } else { "tasks" };
40
41    let mut body: Vec<AnyElement<'a>> = Vec::new();
42    for row in &props.rows {
43        let options = TaskOptions {
44            detailed: props.detailed || row.force_detailed,
45            show_project: true,
46            show_area: false,
47            show_today_markers: true,
48            show_staged_today_marker: false,
49        };
50        let line = if row.task.is_project() {
51            element! {
52                View(flex_direction: FlexDirection::Column, padding_left: 2) {
53                    ProjectItem(project: row.task, options, id_prefix_len)
54                }
55            }
56            .into_any()
57        } else {
58            element! {
59                View(flex_direction: FlexDirection::Column, padding_left: 2) {
60                    TaskItem(task: row.task, options, id_prefix_len)
61                }
62            }
63            .into_any()
64        };
65        body.push(line);
66    }
67
68    element! {
69        View(flex_direction: FlexDirection::Column) {
70            Text(
71                content: format!("{} Find  ({} {})", ICONS.find, count, label),
72                wrap: TextWrap::NoWrap,
73                color: Color::Cyan,
74                weight: Weight::Bold,
75            )
76            Text(content: "", wrap: TextWrap::NoWrap)
77            #(body)
78        }
79    }
80    .into_any()
81}