Coverage Report

Created: 2026-07-21 00:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
super-stt-app/src/core/app/handlers/models_page/install.rs
Line
Count
Source
1
// SPDX-License-Identifier: GPL-3.0-only
2
3
use crate::core::app::AppModel;
4
use crate::ui::messages::{BackendMessage, Message, ModelsPageMessage};
5
use cosmic::prelude::*;
6
7
impl AppModel {
8
0
    pub(in crate::core::app) fn handle_models_install_lifecycle(
9
0
        &mut self,
10
0
        message: ModelsPageMessage,
11
0
    ) -> Task<cosmic::Action<Message>> {
12
0
        match message {
13
            // Registry / Download-tab messages
14
0
            ModelsPageMessage::InstallBackend(source) => {
15
                // Clear a prior "failed to start" so the card reads "Installing…".
16
0
                self.registry.install_errors.remove(&source);
17
0
                let s = source.clone();
18
0
                Task::perform(
19
0
                    async move { crate::daemon::registry::install_by_source(&s).await },
20
0
                    move |res| {
21
0
                        cosmic::Action::App(Message::ModelsPage(match res {
22
0
                            Ok(a) => ModelsPageMessage::InstallAccepted {
23
0
                                source: source.clone(),
24
0
                                install_id: a.install_id,
25
0
                            },
26
0
                            Err(e) => ModelsPageMessage::InstallFailedToStart {
27
0
                                source: source.clone(),
28
0
                                error: e.to_string(),
29
0
                            },
30
                        }))
31
0
                    },
32
                )
33
            }
34
35
0
            ModelsPageMessage::InstallBackendFromRepoUrl(url) => {
36
0
                self.registry.install_errors.remove(&url);
37
0
                let u = url.clone();
38
0
                Task::perform(
39
0
                    async move { crate::daemon::registry::install_by_repo_url(&u).await },
40
0
                    move |res| {
41
0
                        cosmic::Action::App(Message::ModelsPage(match res {
42
0
                            Ok(a) => ModelsPageMessage::InstallAccepted {
43
0
                                source: url.clone(),
44
0
                                install_id: a.install_id,
45
0
                            },
46
0
                            Err(e) => ModelsPageMessage::InstallFailedToStart {
47
0
                                source: url.clone(),
48
0
                                error: e.to_string(),
49
0
                            },
50
                        }))
51
0
                    },
52
                )
53
            }
54
55
0
            ModelsPageMessage::InstallAccepted { source, install_id } => {
56
                use crate::state::registry::InstallStatus;
57
                use super_stt_shared::registry::events::InstallPhase;
58
                // The request was accepted — retire any prior start error.
59
0
                self.registry.install_errors.remove(&source);
60
0
                self.registry.installs.insert(
61
0
                    source,
62
0
                    InstallStatus {
63
0
                        install_id,
64
0
                        phase: InstallPhase::Downloading,
65
0
                        bytes_done: 0,
66
0
                        bytes_total: None,
67
0
                        error: None,
68
0
                    },
69
                );
70
0
                Task::none()
71
            }
72
73
0
            ModelsPageMessage::InstallFailedToStart { source, error } => {
74
0
                log::error!("install({source}) failed to start: {error}");
75
                // Drop the pending marker (there is no background install) and
76
                // record the reason so the Browse card shows "Failed" + a note
77
                // instead of silently snapping back to the Install button.
78
0
                self.registry.installs.remove(&source);
79
0
                self.registry.install_errors.insert(source, error);
80
0
                Task::none()
81
            }
82
83
0
            ModelsPageMessage::UpdateBackend(source) => {
84
0
                self.registry.install_errors.remove(&source);
85
0
                let s = source.clone();
86
0
                Task::perform(
87
0
                    async move { crate::daemon::registry::update(&s).await },
88
0
                    move |res| {
89
0
                        cosmic::Action::App(match res {
90
0
                            Ok(r) if r.noop => {
91
0
                                log::info!("update({source}) noop — already at {}", r.to_version);
92
                                // Nothing to do; let the UI settle naturally.
93
0
                                Message::Backend(BackendMessage::BackendsReload)
94
                            }
95
0
                            Ok(r) => Message::ModelsPage(ModelsPageMessage::InstallAccepted {
96
0
                                source: source.clone(),
97
0
                                install_id: r.install_id.unwrap_or_default(),
98
0
                            }),
99
0
                            Err(e) => {
100
0
                                Message::ModelsPage(ModelsPageMessage::InstallFailedToStart {
101
0
                                    source: source.clone(),
102
0
                                    error: e.to_string(),
103
0
                                })
104
                            }
105
                        })
106
0
                    },
107
                )
108
            }
109
110
0
            _ => Task::none(),
111
        }
112
0
    }
113
114
    /// Uninstall lifecycle: kick off the request and surface its failure.
115
0
    pub(in crate::core::app) fn handle_models_uninstall(
116
0
        &mut self,
117
0
        message: ModelsPageMessage,
118
0
    ) -> Task<cosmic::Action<Message>> {
119
0
        match message {
120
0
            ModelsPageMessage::UninstallBackend(source) => {
121
                // Clear any stale failure so the row reads "in progress" on retry.
122
0
                self.registry.uninstall_errors.remove(&source);
123
0
                let s = source.clone();
124
0
                Task::perform(
125
0
                    async move { crate::daemon::registry::uninstall(&s).await },
126
0
                    move |res| {
127
0
                        cosmic::Action::App(match res {
128
0
                            Ok(_) => Message::Backend(BackendMessage::BackendsReload),
129
0
                            Err(error) => Message::ModelsPage(ModelsPageMessage::UninstallFailed {
130
0
                                source: source.clone(),
131
0
                                error: error.to_string(),
132
0
                            }),
133
                        })
134
0
                    },
135
                )
136
            }
137
138
0
            ModelsPageMessage::UninstallFailed { source, error } => {
139
0
                log::error!("uninstall({source}) failed: {error}");
140
0
                self.registry.uninstall_errors.insert(source, error);
141
0
                Task::none()
142
            }
143
144
0
            _ => Task::none(),
145
        }
146
0
    }
147
148
0
    pub(in crate::core::app) fn handle_models_install_progress(
149
0
        &mut self,
150
0
        message: ModelsPageMessage,
151
0
    ) -> Task<cosmic::Action<Message>> {
152
0
        match message {
153
            ModelsPageMessage::InstallProgress {
154
0
                install_id,
155
0
                source,
156
0
                phase,
157
0
                bytes_done,
158
0
                bytes_total,
159
            } => {
160
0
                if let Some(s) = self.registry.installs.get_mut(&source)
161
0
                    && s.install_id == install_id
162
                {
163
0
                    s.phase = phase;
164
0
                    if let Some(d) = bytes_done {
165
0
                        s.bytes_done = d;
166
0
                    }
167
0
                    if let Some(t) = bytes_total {
168
0
                        s.bytes_total = Some(t);
169
0
                    }
170
0
                }
171
0
                Task::none()
172
            }
173
174
0
            ModelsPageMessage::InstallCompleted { source } => {
175
0
                self.registry.installs.remove(&source);
176
0
                self.registry.install_errors.remove(&source);
177
                // Refresh the installed-backends list so the new install
178
                // shows up in the Installed tab.
179
0
                crate::core::app::handlers::tasks::reload_backends()
180
            }
181
182
            ModelsPageMessage::InstallFailed {
183
0
                install_id,
184
0
                source,
185
0
                phase,
186
0
                error,
187
            } => {
188
0
                if let Some(s) = self.registry.installs.get_mut(&source)
189
0
                    && s.install_id == install_id
190
0
                {
191
0
                    s.error = Some(error);
192
0
                    s.phase = phase;
193
0
                }
194
0
                Task::none()
195
            }
196
197
0
            _ => Task::none(),
198
        }
199
0
    }
200
}