things3_cloud/ui/components/
progress_badge.rs1use crate::common::ICONS;
2use crate::store::{Task, ThingsStore};
3use iocraft::prelude::*;
4use std::sync::Arc;
5
6#[derive(Default, Props)]
7pub struct ProgressBadgeProps<'a> {
8 pub project: Option<&'a Task>,
9 pub show_count: bool,
10 pub title: Option<String>,
11 pub color: Option<Color>,
12 pub weight: Weight,
13}
14
15#[component]
16pub fn ProgressBadge<'a>(
17 hooks: Hooks,
18 props: &ProgressBadgeProps<'a>,
19) -> impl Into<AnyElement<'a>> {
20 let Some(project) = props.project else {
21 return element!(Fragment).into_any();
22 };
23
24 let store = hooks.use_context::<Arc<ThingsStore>>().clone();
25 let progress = project_progress(project, store.as_ref());
26 let color = props.color.unwrap_or(Color::DarkGrey);
27 let weight = props.weight;
28
29 let title = if let Some(title) = &props.title {
30 element!(Text(content: title.clone(), color, weight)).into_any()
31 } else {
32 element!(Fragment).into_any()
33 };
34
35 let count = if props.show_count {
36 let content = format!("({}/{})", progress.done, progress.done + progress.total);
37 element!(Text(content, color, weight)).into_any()
38 } else {
39 element!(Fragment).into_any()
40 };
41
42 element! {
43 View(flex_direction: FlexDirection::Row, gap: 1) {
44 Text(content: progress.marker, color, weight)
45 #(title)
46 #(count)
47 }
48 }
49 .into_any()
50}
51
52struct Progress {
53 marker: &'static str,
54 total: i32,
55 done: i32,
56}
57
58fn project_progress(project: &Task, store: &ThingsStore) -> Progress {
59 if project.in_someday() {
60 return Progress {
61 marker: ICONS.project_someday,
62 total: 0,
63 done: 0,
64 };
65 }
66
67 let progress = store.project_progress(&project.uuid);
68 let total = progress.total;
69 let done = progress.done;
70
71 if total == 0 || done == 0 {
72 return Progress {
73 marker: ICONS.progress_empty,
74 total,
75 done,
76 };
77 }
78
79 if done == total {
80 return Progress {
81 marker: ICONS.progress_full,
82 total,
83 done,
84 };
85 }
86
87 let ratio = done as f32 / total as f32;
88 let marker = if ratio < (1.0 / 3.0) {
89 ICONS.progress_quarter
90 } else if ratio < (2.0 / 3.0) {
91 ICONS.progress_half
92 } else {
93 ICONS.progress_three_quarter
94 };
95
96 Progress {
97 marker,
98 total,
99 done,
100 }
101}