Skip to main content

egui_cha/
app.rs

1//! Core App trait - The heart of TEA
2
3use crate::{error::FrameworkError, sub::Sub, Cmd, ViewCtx};
4
5/// The main application trait following TEA (The Elm Architecture)
6///
7/// # Type Parameters
8/// - `Model`: Application state
9/// - `Msg`: Message type for state updates
10///
11/// # Example
12/// ```ignore
13/// struct MyApp;
14///
15/// impl App for MyApp {
16///     type Model = AppModel;
17///     type Msg = AppMsg;
18///
19///     fn init() -> (Self::Model, Cmd<Self::Msg>) {
20///         (AppModel::default(), Cmd::none())
21///     }
22///
23///     fn update(model: &mut Self::Model, msg: Self::Msg) -> Cmd<Self::Msg> {
24///         match msg {
25///             AppMsg::Increment => model.count += 1,
26///             AppMsg::Decrement => model.count -= 1,
27///         }
28///         Cmd::none()
29///     }
30///
31///     fn view(model: &Self::Model, ctx: &mut ViewCtx<Self::Msg>) {
32///         ctx.ui.label(format!("Count: {}", model.count));
33///     }
34/// }
35/// ```
36pub trait App: Sized + 'static {
37    /// Application state
38    type Model: Send + 'static;
39
40    /// Message type for triggering state updates
41    type Msg: Clone + Send + 'static;
42
43    /// Initialize the application with initial model and optional commands
44    fn init() -> (Self::Model, Cmd<Self::Msg>);
45
46    /// Update the model based on a message, optionally returning commands
47    fn update(model: &mut Self::Model, msg: Self::Msg) -> Cmd<Self::Msg>;
48
49    /// Render the view - use `ctx.emit()` to dispatch messages
50    fn view(model: &Self::Model, ctx: &mut ViewCtx<Self::Msg>);
51
52    /// Declare subscriptions based on current model state
53    ///
54    /// Called each frame. The runtime manages starting/stopping
55    /// subscriptions as they appear or disappear.
56    ///
57    /// # Example
58    /// ```ignore
59    /// fn subscriptions(model: &Model) -> Sub<Msg> {
60    ///     if model.auto_refresh {
61    ///         Sub::interval("refresh", Duration::from_secs(30), Msg::Refresh)
62    ///     } else {
63    ///         Sub::none()
64    ///     }
65    /// }
66    /// ```
67    fn subscriptions(_model: &Self::Model) -> Sub<Self::Msg> {
68        Sub::none()
69    }
70
71    /// Handle framework errors
72    ///
73    /// Called when the framework encounters an internal error (task panic,
74    /// runtime failure, etc.). Override this to integrate with your app's
75    /// error handling.
76    ///
77    /// Default implementation logs to tracing and continues.
78    ///
79    /// # Example
80    /// ```ignore
81    /// fn on_framework_error(model: &mut Model, err: FrameworkError) -> Cmd<Msg> {
82    ///     // Add to your error console
83    ///     model.errors.push_with_level(&err.message, err.severity.into());
84    ///
85    ///     // Or convert to your app's error type
86    ///     Cmd::msg(Msg::Error(err.format_message()))
87    /// }
88    /// ```
89    fn on_framework_error(_model: &mut Self::Model, err: FrameworkError) -> Cmd<Self::Msg> {
90        err.log();
91        Cmd::none()
92    }
93}