Skip to main content

things3_cloud/ui/views/
find.rs

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