forked from 1b-agent/fieldcraft-upstream
UI: update notice, Help › Check for Updates and Reinstall, Settings › Updates (#231)
The window checks at start-up at most once a day when automatic checks are on (Settings and
the first run's question), never while that question is open and never without a host, so the
browser and tests make no network call. A newer release shows a quiet notice in the status bar
("FieldCraft X is available — What's new · Install · Skip"); Install downloads and verifies
through the host, then asks to restart, saving or asking about unsaved changes first, and the
host swaps the release in after the window closes. A .deb/.rpm install offers the system's
installer and the command instead. Skip this version is kept in the preferences.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
This commit is contained in:
1 parent
69c1440cbe
commit
2e28a69c04
9 files changed
+664
-9
No files matched your search
@@ -126,7 +126,7 @@ impl ModelApp {
|
||||
r
|
||||
}
|
||||
|
||||
fn open_link(&mut self, ctx: &egui::Context, url: &str) {
|
||||
pub(crate) fn open_link(&mut self, ctx: &egui::Context, url: &str) {
|
||||
match &self.services.open_url {
|
||||
Some(open) => {
|
||||
if let Err(e) = open(url) {
|
||||
@@ -143,7 +143,7 @@ pub fn show(app: &mut ModelApp, ctx: &egui::Context) {
|
||||
let t = crate::theme::Tokens::get(app.ui.dark);
|
||||
match app.prompt {
|
||||
Some(Prompt::Consent) => {
|
||||
let (mut share, mut decline, mut link) = (false, false, false);
|
||||
let (mut share, mut decline, mut link, mut updates) = (false, false, false, None);
|
||||
crate::frame::window(ctx, "Help Improve FieldCraft", crate::frame::Width::Normal).id(egui::Id::new("fc_consent")).show(ctx, |ui| {
|
||||
ui.label(QUESTION);
|
||||
ui.add_space(4.0);
|
||||
@@ -151,6 +151,10 @@ pub fn show(app: &mut ModelApp, ctx: &egui::Context) {
|
||||
ui.add_space(2.0);
|
||||
ui.label(RichText::new("You can change this any time in Help › Settings.").color(t.text_dim).size(11.0));
|
||||
link = ui.link("What is sent (docs/privacy.md)").on_hover_text(PRIVACY_URL).clicked();
|
||||
if app.updates_available() {
|
||||
ui.add_space(4.0);
|
||||
updates = update_check(ui, &t, app.prefs.update_check);
|
||||
}
|
||||
ui.add_space(6.0);
|
||||
ui.horizontal(|ui| {
|
||||
share = ui.button("Share Anonymous Usage").clicked();
|
||||
@@ -160,6 +164,9 @@ pub fn show(app: &mut ModelApp, ctx: &egui::Context) {
|
||||
if link {
|
||||
app.open_link(ctx, PRIVACY_URL);
|
||||
}
|
||||
if let Some(on) = updates {
|
||||
app.set_update_prefs(on, None);
|
||||
}
|
||||
if share {
|
||||
app.answer_consent(true);
|
||||
} else if decline || ctx.input(|i| i.key_pressed(egui::Key::Escape)) {
|
||||
@@ -169,8 +176,20 @@ pub fn show(app: &mut ModelApp, ctx: &egui::Context) {
|
||||
Some(Prompt::Settings) => {
|
||||
let available = app.usage_available();
|
||||
let (mut sharing, mut automation) = (app.prefs.usage_sharing == Some(true), app.prefs.usage_automation);
|
||||
let (mut close, mut link) = (false, false);
|
||||
let (mut close, mut link, mut updates, mut unskip, mut check) = (false, false, None, false, false);
|
||||
crate::frame::window(ctx, "Settings", crate::frame::Width::Normal).id(egui::Id::new("fc_settings")).show(ctx, |ui| {
|
||||
if app.updates_available() {
|
||||
crate::frame::menu_heading(ui, &t, "UPDATES");
|
||||
updates = update_check(ui, &t, app.prefs.update_check);
|
||||
ui.horizontal(|ui| {
|
||||
check = ui.button("Check Now").on_hover_text("Help › Check for Updates").clicked();
|
||||
if !app.prefs.update_skip.is_empty() {
|
||||
ui.label(RichText::new(format!("Skipping FieldCraft {}", app.prefs.update_skip)).color(t.text_dim).size(11.0));
|
||||
unskip = ui.small_button("Offer It Again").clicked();
|
||||
}
|
||||
});
|
||||
ui.add_space(6.0);
|
||||
}
|
||||
crate::frame::menu_heading(ui, &t, "PRIVACY");
|
||||
ui.add_enabled(available, egui::Checkbox::new(&mut sharing, "Share anonymous usage")).on_hover_text(QUESTION);
|
||||
ui.indent("fc_usage_automation", |ui| {
|
||||
@@ -199,6 +218,12 @@ pub fn show(app: &mut ModelApp, ctx: &egui::Context) {
|
||||
if available && (sharing != (app.prefs.usage_sharing == Some(true)) || automation != app.prefs.usage_automation) {
|
||||
app.set_usage(sharing, automation);
|
||||
}
|
||||
if updates.is_some() || unskip {
|
||||
app.set_update_prefs(updates.unwrap_or(app.prefs.update_check), unskip.then(String::new));
|
||||
}
|
||||
if check {
|
||||
app.check_for_updates();
|
||||
}
|
||||
if link {
|
||||
app.open_link(ctx, PRIVACY_URL);
|
||||
}
|
||||
@@ -210,6 +235,23 @@ pub fn show(app: &mut ModelApp, ctx: &egui::Context) {
|
||||
}
|
||||
}
|
||||
|
||||
/// The automatic update check's checkbox; the new value when it was clicked.
|
||||
fn update_check(ui: &mut egui::Ui, t: &crate::theme::Tokens, on: bool) -> Option<bool> {
|
||||
let mut checked = on;
|
||||
let changed = ui
|
||||
.checkbox(&mut checked, "Check for updates automatically")
|
||||
.on_hover_text(
|
||||
"At start-up, at most once a day, FieldCraft asks GitHub Releases for the latest version. Nothing installs until you choose Install.",
|
||||
)
|
||||
.changed();
|
||||
ui.label(
|
||||
RichText::new("The check sends only the request (your IP address and the FieldCraft version reach GitHub); off means no check.")
|
||||
.color(t.text_dim)
|
||||
.size(11.0),
|
||||
);
|
||||
changed.then_some(checked)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use fieldcraft_engine::Session;
|
||||
|
||||
Reference in new issue
Block a user