fix failed full weather fetch and implement cache for full
This commit is contained in:
parent
e155018474
commit
21a2e5299c
1 changed files with 31 additions and 3 deletions
34
src/app.rs
34
src/app.rs
|
|
@ -51,6 +51,10 @@ pub struct AppModel {
|
|||
last_updated: String,
|
||||
/// Full weather report for popup
|
||||
full_weather: String,
|
||||
/// Last error from a full-weather fetch, if any. Kept separate from
|
||||
/// `full_weather` so that a failed fetch does not poison the cache
|
||||
/// and block the next popup-open from retrying.
|
||||
full_weather_error: Option<String>,
|
||||
/// Loading state
|
||||
is_loading: bool,
|
||||
/// Popup window ID
|
||||
|
|
@ -102,6 +106,7 @@ impl cosmic::Application for AppModel {
|
|||
location: String::new(),
|
||||
last_updated: String::new(),
|
||||
full_weather: String::new(),
|
||||
full_weather_error: None,
|
||||
is_loading: true,
|
||||
popup: None,
|
||||
rectangle: Rectangle::default(),
|
||||
|
|
@ -175,11 +180,24 @@ impl cosmic::Application for AppModel {
|
|||
}
|
||||
|
||||
fn view_window(&self, _id: window::Id) -> Element<'_, Self::Message> {
|
||||
// Pick what to render: the cached forecast, a transient error
|
||||
// (not stored in `full_weather` so the next open retries), or a
|
||||
// loading placeholder while the in-flight request completes.
|
||||
let display_text: String = if !self.full_weather.is_empty() {
|
||||
self.full_weather.clone()
|
||||
} else if let Some(err) = &self.full_weather_error {
|
||||
format!(
|
||||
"Failed to load weather:\n{err}\n\nClose and reopen to retry."
|
||||
)
|
||||
} else {
|
||||
"Loading…".to_string()
|
||||
};
|
||||
|
||||
// Calculate the width needed for the monospace content.
|
||||
// The default monospace font is ~8.4px per character at 14px font size,
|
||||
// plus padding for container (12*2) and popup chrome (~32).
|
||||
#[allow(clippy::cast_precision_loss)]
|
||||
let max_line_len = self.full_weather.lines()
|
||||
let max_line_len = display_text.lines()
|
||||
.map(|line| line.chars().count())
|
||||
.max()
|
||||
.unwrap_or(40) as f32;
|
||||
|
|
@ -188,7 +206,7 @@ impl cosmic::Application for AppModel {
|
|||
let popup_width = content_width.max(400.0);
|
||||
|
||||
let content = container(
|
||||
widget::text(&self.full_weather)
|
||||
widget::text(display_text)
|
||||
.font(Font::MONOSPACE)
|
||||
.wrapping(cosmic::iced::widget::text::Wrapping::None)
|
||||
.width(cosmic::iced::Length::Fixed(content_width))
|
||||
|
|
@ -351,16 +369,25 @@ impl cosmic::Application for AppModel {
|
|||
match result {
|
||||
Ok(weather) => {
|
||||
self.full_weather = weather;
|
||||
self.full_weather_error = None;
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Full weather fetch error: {e}");
|
||||
self.full_weather = "Failed to load weather".to_string();
|
||||
// Leave `full_weather` empty so that the next
|
||||
// popup open triggers a refetch (see toggle_popup).
|
||||
self.full_weather_error = Some(e);
|
||||
}
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
Message::RefreshWeather => {
|
||||
self.retry_count = 0;
|
||||
// Invalidate the popup cache on each scheduled refresh so
|
||||
// that the next popup open fetches a fresh forecast. This
|
||||
// piggybacks the popup's freshness on the panel's 15-minute
|
||||
// refresh cadence (WEATHER_UPDATE_INTERVAL_MINUTES).
|
||||
self.full_weather.clear();
|
||||
self.full_weather_error = None;
|
||||
let units = self.units;
|
||||
Task::perform(fetch_weather(units), |result| {
|
||||
cosmic::Action::App(Message::WeatherUpdate(result))
|
||||
|
|
@ -371,6 +398,7 @@ impl cosmic::Application for AppModel {
|
|||
self.retry_count = 0;
|
||||
// Clear cached full weather so the popup re-fetches on next open
|
||||
self.full_weather.clear();
|
||||
self.full_weather_error = None;
|
||||
let units = self.units;
|
||||
Task::perform(fetch_weather(units), |result| {
|
||||
cosmic::Action::App(Message::WeatherUpdate(result))
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue