Add optional hosted desktop editing with conditional source saves

This commit is contained in:
2026-09-06 07:23:18 +03:00
parent 49a2446f85
commit 1b80671dd0
12 changed files with 2647 additions and 16 deletions
+30 -3
View File
@@ -1,3 +1,4 @@
mod hosted;
use crate::forms::Draft;
use crate::{
document::Document,
@@ -280,6 +281,7 @@ impl std::fmt::Display for Choice {
}
#[derive(Debug, Clone, Copy)]
pub enum Pending {
HostedOpen,
New,
Demo,
Open,
@@ -299,6 +301,7 @@ pub struct FilePrompt {
#[derive(Debug, Clone)]
pub enum Message {
Hosted(crate::hosted::Event),
PortAnchor(crate::port_edit::Event),
Connection(crate::connection_edit::Event),
Menu(crate::model_menu::Event),
@@ -410,6 +413,7 @@ pub enum Message {
}
pub struct App {
pub hosted: crate::hosted::State,
pub connection: Option<crate::connection_edit::Session>,
pub model_menu: Option<crate::model_menu::Opened>,
pub source_tree: crate::source_tree::State,
@@ -525,6 +529,7 @@ impl App {
Kind::Activity
},
status: "Coastal rescue example · explore both engineering perspectives".into(),
hosted: Default::default(),
busy: false,
pending: None,
delete_pending: false,
@@ -844,7 +849,10 @@ impl App {
let source_version = self.source_version + 1;
let lint_running = self.lint_running;
let guide = std::mem::take(&mut self.guide);
let mut hosted = std::mem::take(&mut self.hosted);
hosted.leave_document();
*self = Self::with_project(project);
self.hosted = hosted;
self.window_size = window_size;
self.canvas_size = canvas_size;
self.source_version = source_version;
@@ -906,8 +914,12 @@ impl App {
}
}
pub fn view(&self) -> Element<'_, Message> {
crate::context_menu::Popup::new(crate::views::view(self), crate::model_menu::popup(self))
.into()
let base = crate::context_menu::Popup::new(
crate::views::view(self),
crate::model_menu::popup(self),
)
.into();
crate::hosted::view::overlay(self, base)
}
pub fn subscription(&self) -> Subscription<Message> {
Subscription::batch([
@@ -1019,6 +1031,7 @@ impl App {
&& !matches!(
message,
Message::Saved(_)
| Message::Hosted(crate::hosted::Event::Completed(..))
| Message::Loaded(_)
| Message::IncludesLoaded(_, _)
| Message::SavePath(_)
@@ -1038,6 +1051,10 @@ impl App {
message,
Message::Escape | Message::Request(Pending::Close(_))
) {
if self.hosted.visible {
self.hosted.visible = false;
return Task::none();
}
if self.workflow.take().is_some() {
return Task::none();
}
@@ -1062,6 +1079,7 @@ impl App {
| Message::Lint(_)
| Message::Linted(_, _)
| Message::Saved(_)
| Message::Hosted(crate::hosted::Event::Completed(..))
| Message::Loaded(_)
| Message::IncludesLoaded(_, _)
| Message::SavePath(_)
@@ -1069,7 +1087,8 @@ impl App {
| Message::Exported(_)
);
if !modal_event
&& ((self.workflow.is_some() && !matches!(message, Message::Workflow(_)))
&& ((self.hosted.visible && !matches!(message, Message::Hosted(_)))
|| (self.workflow.is_some() && !matches!(message, Message::Workflow(_)))
|| (self.file_prompt.is_some()
&& !matches!(
message,
@@ -1187,6 +1206,7 @@ impl App {
}
fn handle(&mut self, message: Message) -> Task<Message> {
match message {
Message::Hosted(event) => return self.hosted_event(event),
Message::ScenarioCanvas(event) => {
use crate::behavior::scenario::{self, CanvasEvent};
let context = event.context();
@@ -2490,6 +2510,9 @@ impl App {
return self.handle(Message::Save(false));
}
Message::Save(save_as) => {
if !save_as && self.hosted.session.is_some() {
return self.save_hosted();
}
if !self.apply_behavior() || !self.apply_source() || !self.apply() {
self.continue_after_save = false;
self.pending = None;
@@ -2541,6 +2564,9 @@ impl App {
}
self.disk_project = Some(disk);
self.path = Some(receipt.path);
self.hosted.session = None;
self.hosted.review = None;
self.hosted.uncertain = None;
self.document.mark_saved(receipt.snapshot);
self.prune_closed_files(!self.document.dirty());
self.status = "All source files saved".into();
@@ -2879,6 +2905,7 @@ impl App {
fn proceed(&mut self, pending: Pending) -> Task<Message> {
self.pending = None;
match pending {
Pending::HostedOpen => self.open_hosted(),
Pending::New => {
self.reset(Project::empty(), None);
Task::none()