maycoon_widgets/
fetcher.rs1use maycoon_core::app::context::AppContext;
2use maycoon_core::app::info::AppInfo;
3use maycoon_core::app::update::Update;
4use maycoon_core::layout::{LayoutNode, LayoutStyle, StyleNode};
5use maycoon_core::tasks;
6use maycoon_core::vg::Scene;
7use maycoon_core::widget::Widget;
8use maycoon_theme::id::WidgetId;
9use maycoon_theme::theme::Theme;
10use std::future::Future;
11use std::sync::{Arc, Mutex};
12
13pub struct WidgetFetcher<T: Send + 'static, W: Widget, F: Fn(Option<T>) -> W> {
29 result: Arc<Mutex<Option<T>>>,
30 render: F,
31 widget: Option<W>,
32 update: Update,
33}
34
35impl<T: Send + 'static, W: Widget, F: Fn(Option<T>) -> W> WidgetFetcher<T, W, F> {
36 pub fn new<Fut>(future: Fut, update: Update, render: F) -> Self
41 where
42 Fut: Future<Output = T> + Send + 'static,
43 {
44 let result = Arc::new(Mutex::new(None));
45
46 let result_clone = result.clone();
47 tasks::spawn(async move {
48 let out = future.await;
49 *result_clone.lock().expect("failed to lock result") = Some(out);
50 })
51 .forget();
52
53 Self {
54 result,
55 render,
56 widget: None,
57 update,
58 }
59 }
60}
61
62impl<T: Send + 'static, W: Widget, F: Fn(Option<T>) -> W> Widget for WidgetFetcher<T, W, F> {
63 fn render(
64 &mut self,
65 scene: &mut Scene,
66 theme: &mut dyn Theme,
67 layout_node: &LayoutNode,
68 info: &AppInfo,
69 context: AppContext,
70 ) {
71 if let Some(widget) = &mut self.widget {
72 widget.render(scene, theme, layout_node, info, context.clone())
73 }
74 }
75
76 fn layout_style(&self) -> StyleNode {
77 if let Some(widget) = &self.widget {
78 widget.layout_style()
79 } else {
80 StyleNode {
81 style: LayoutStyle::default(),
82 children: Vec::new(),
83 }
84 }
85 }
86
87 fn update(&mut self, layout: &LayoutNode, context: AppContext, info: &AppInfo) -> Update {
88 let mut update = Update::empty();
89
90 if let Some(result) = self.result.lock().expect("failed to lock result").take() {
91 self.widget = Some((self.render)(Some(result)));
92 update = self.update;
93 } else if self.widget.is_none() {
94 self.widget = Some((self.render)(None));
95 update = self.update;
96 }
97
98 self.widget.as_mut().unwrap().update(layout, context, info) | update
100 }
101
102 fn widget_id(&self) -> WidgetId {
103 if let Some(widget) = &self.widget {
104 widget.widget_id()
105 } else {
106 WidgetId::new("maycoon-widgets", "WidgetFetcher")
107 }
108 }
109}