forked from 1b-agent/opencadstudio-upstream
[IMP] OneBSpace rebrand of OpenCADStudio -> OneCAD Draft (wordmark, about, crash banner, 23 locales; strip SW/manifest; air-gap: update check, donations, discussions, external help links)
This commit is contained in:
1 parent
c9e763006e
commit
193f2ae9ab
57 files changed
+760
-1091
No files matched your search
@@ -114,7 +114,7 @@ fn route(path: &str, format: Option<usize>) -> Result<Route, String> {
|
||||
.find(|f| f.extensions.iter().any(|e| e.eq_ignore_ascii_case(&ext)));
|
||||
Err(match named.and_then(|f| unsupported_reason(f.support).map(|r| (f, r))) {
|
||||
Some((f, reason)) => format!("{}: {reason}", f.name),
|
||||
None => crate::t!("OpenCAD Studio has no importer for this format.").into_owned(),
|
||||
None => crate::t!("OneCAD Draft has no importer for this format.") /* OneBSpace (OneCAD Draft): rebranded */.into_owned(),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
+13
-55
@@ -69,33 +69,15 @@ fn ensure_draw_order_table(doc: &mut codec::CadDocument, block: codec::Handle) -
|
||||
impl OpenCADStudio {
|
||||
pub(crate) fn dispatch_view(&mut self, cmd: &str, i: usize) -> Option<Task<Message>> {
|
||||
match cmd {
|
||||
"DONATE" => {
|
||||
self.command_line
|
||||
.push_info(crate::t!("Opening Patreon page...").as_ref());
|
||||
return Some(crate::sys::open_url(
|
||||
"https://patreon.com/HakanSeven12",
|
||||
self.main_window,
|
||||
));
|
||||
}
|
||||
// OneBSpace (OneCAD Draft): donations disabled — air-gapped build.
|
||||
"DONATE" => Some(Task::none()),
|
||||
|
||||
"WEBVERSION" => {
|
||||
self.command_line
|
||||
.push_info(crate::t!("Opening OCS Web...").as_ref());
|
||||
return Some(crate::sys::open_url(
|
||||
"https://hakanseven12.github.io/OpenCADStudio/",
|
||||
self.main_window,
|
||||
));
|
||||
}
|
||||
// OneBSpace (OneCAD Draft): the upstream web-app link is gone.
|
||||
"WEBVERSION" => Some(Task::none()),
|
||||
|
||||
"HELP" => {
|
||||
self.command_line.push_info(
|
||||
crate::t!("Opening OCS Discussions for help and questions...").as_ref(),
|
||||
);
|
||||
return Some(crate::sys::open_url(
|
||||
"https://github.com/HakanSeven12/OpenCADStudio/discussions",
|
||||
self.main_window,
|
||||
));
|
||||
}
|
||||
// OneBSpace (OneCAD Draft): external help/discussions link removed —
|
||||
// air-gapped build. Use the in-app help instead.
|
||||
"HELP" => Some(Task::none()),
|
||||
|
||||
// ── DWGPROPS — print round-trip-only HeaderVariables ─────────
|
||||
// No UI dialog for these yet; the command surfaces them so
|
||||
@@ -317,28 +299,9 @@ impl OpenCADStudio {
|
||||
}
|
||||
}
|
||||
|
||||
"REPORT" => {
|
||||
// Pre-fill the GitHub issue body with version + platform so
|
||||
// reports arrive with the basics already filled in. The rule
|
||||
// is `***`: text typed right above a `---` line turns into a
|
||||
// Markdown heading.
|
||||
let body = format!(
|
||||
"<!-- Describe the issue and the steps to reproduce it. -->\n\n\n\
|
||||
***\n- Open CAD Studio: v{}\n- Revision: {} ({}, {})\n- Platform: {}\n",
|
||||
env!("OCS_FULL_VERSION"),
|
||||
env!("OCS_GIT_REV"),
|
||||
env!("OCS_COMMIT_DATE"),
|
||||
env!("OCS_BUILD_PROFILE"),
|
||||
crate::sys::platform_info(),
|
||||
);
|
||||
let url = format!(
|
||||
"https://github.com/HakanSeven12/OpenCADStudio/issues/new?body={}",
|
||||
crate::sys::percent_encode(&body)
|
||||
);
|
||||
self.command_line
|
||||
.push_info(crate::t!("Opening feedback page...").as_ref());
|
||||
return Some(crate::sys::open_url(&url, self.main_window));
|
||||
}
|
||||
// OneBSpace (OneCAD Draft): the upstream GitHub issue tracker is
|
||||
// unreachable from an air-gapped build; feedback is a no-op.
|
||||
"REPORT" => Some(Task::none()),
|
||||
|
||||
"ABOUT" => {
|
||||
return Some(Task::done(Message::AboutOpen));
|
||||
@@ -348,14 +311,9 @@ impl OpenCADStudio {
|
||||
return Some(Task::done(Message::PluginManagerOpen));
|
||||
}
|
||||
|
||||
"CHANGELOG" => {
|
||||
self.command_line
|
||||
.push_info(crate::t!("Opening release notes...").as_ref());
|
||||
return Some(crate::sys::open_url(
|
||||
"https://github.com/HakanSeven12/OpenCADStudio/releases",
|
||||
self.main_window,
|
||||
));
|
||||
}
|
||||
// OneBSpace (OneCAD Draft): upstream release notes are unreachable
|
||||
// from an air-gapped build.
|
||||
"CHANGELOG" => Some(Task::none()),
|
||||
|
||||
// ── ALIASEDIT — command-alias editor ───────────────────────────
|
||||
// Opens the command-alias table editor (ocad.pgp). Keyboard
|
||||
|
||||
+18
-44
@@ -5469,54 +5469,26 @@ impl OpenCADStudio {
|
||||
)
|
||||
};
|
||||
s.queue_startup_prompts();
|
||||
// Fetch the Patreon supporters list once at boot for the Start page.
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let patrons_fetch = Task::perform(
|
||||
async { crate::patreon::fetch_patrons() },
|
||||
Message::PatronsFetched,
|
||||
);
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
// OneBSpace (OneCAD Draft): Patreon supporters fetch disabled — air-gapped
|
||||
// build. The Start page supporters rail renders from the local list only.
|
||||
let patrons_fetch = Task::none();
|
||||
// Tutorial videos: show the on-disk cache instantly, refresh from the
|
||||
// live playlist in the background. Nothing ships in the binary. The
|
||||
// fetch runs on its own OS thread — its several sequential HTTP
|
||||
// requests would otherwise sit on the async executor and hold up the
|
||||
// rest of the boot tasks (the Start page waited on it).
|
||||
// OneBSpace (OneCAD Draft): tutorial videos show the local on-disk
|
||||
// cache only — no playlist refresh, no thumbnail downloads (air-gapped).
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let videos_fetch = {
|
||||
s.set_videos(crate::videos::load_cached());
|
||||
s.videos_loading = true;
|
||||
let (tx, rx) = iced::futures::channel::oneshot::channel();
|
||||
std::thread::spawn(move || {
|
||||
let _ = tx.send(crate::videos::fetch_playlist());
|
||||
});
|
||||
Task::perform(
|
||||
async move {
|
||||
rx.await
|
||||
.unwrap_or_else(|_| Err("video fetch thread died".into()))
|
||||
},
|
||||
Message::VideosFetched,
|
||||
)
|
||||
s.videos_loading = false;
|
||||
Task::none()
|
||||
};
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
let videos_fetch = Task::none();
|
||||
// GitHub Discussions: seed from the last successful fetch, then refresh
|
||||
// the public feed and pinned section on a background thread.
|
||||
// OneBSpace (OneCAD Draft): GitHub Discussions refresh disabled —
|
||||
// air-gapped build. The Start page lists the bundled discussions.json.
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let discussions_fetch = {
|
||||
s.discussions = crate::discussions::load_cached();
|
||||
s.discussions_loading = true;
|
||||
let (tx, rx) = iced::futures::channel::oneshot::channel();
|
||||
std::thread::spawn(move || {
|
||||
let _ = tx.send(crate::discussions::fetch_discussions());
|
||||
});
|
||||
Task::perform(
|
||||
async move {
|
||||
rx.await
|
||||
.unwrap_or_else(|_| Err("discussion fetch thread died".into()))
|
||||
},
|
||||
Message::DiscussionsFetched,
|
||||
)
|
||||
s.discussions_loading = false;
|
||||
Task::none()
|
||||
};
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
let discussions_fetch = Task::none();
|
||||
@@ -5565,9 +5537,11 @@ impl OpenCADStudio {
|
||||
Task::done(Message::PollWebFonts),
|
||||
Task::done(Message::ApplyWebFont(primary_font)),
|
||||
]);
|
||||
// Web can't reach the Patreon API directly (CORS); fetch the CI-built
|
||||
// supporters.json served on the same origin instead.
|
||||
let patrons = Task::perform(crate::patreon::fetch_patrons_web(), Message::PatronsFetched);
|
||||
// OneBSpace (OneCAD Draft): Patreon supporters fetch disabled — air-gapped
|
||||
// build (no Patreon API, no supporters.json).
|
||||
let patrons = Task::none();
|
||||
// Videos/discussions read the LOCAL same-origin videos.json /
|
||||
// discussions.json shipped next to the app; no remote endpoints.
|
||||
s.videos_loading = true;
|
||||
let videos = Task::perform(crate::videos::fetch_playlist_web(), Message::VideosFetched);
|
||||
s.discussions_loading = true;
|
||||
@@ -5662,13 +5636,13 @@ pub fn run() -> iced::Result {
|
||||
let dot = if tab.dirty { "● " } else { "" };
|
||||
let name = tab.tab_display_name();
|
||||
format!(
|
||||
"{}Open CAD Studio {} - {}",
|
||||
"{}OneCAD Draft {} - {}", // OneBSpace (OneCAD Draft): rebranded wordmark
|
||||
dot,
|
||||
env!("OCS_APP_VERSION"),
|
||||
name
|
||||
)
|
||||
} else {
|
||||
concat!("Open CAD Studio ", env!("OCS_APP_VERSION")).to_string()
|
||||
concat!("OneCAD Draft ", env!("OCS_APP_VERSION")).to_string() // OneBSpace (OneCAD Draft): rebranded wordmark
|
||||
}
|
||||
})
|
||||
.theme(|state: &OpenCADStudio, _| state.active_theme.clone())
|
||||
@@ -5714,7 +5688,7 @@ pub fn run_web() -> iced::Result {
|
||||
)
|
||||
.subscription(OpenCADStudio::subscription)
|
||||
.title(|_state: &OpenCADStudio| {
|
||||
concat!("Open CAD Studio ", env!("OCS_APP_VERSION")).to_string()
|
||||
concat!("OneCAD Draft ", env!("OCS_APP_VERSION")).to_string() // OneBSpace (OneCAD Draft): rebranded wordmark
|
||||
})
|
||||
.theme(|state: &OpenCADStudio| state.active_theme.clone())
|
||||
.backend(iced::Backend::Hardware(iced::backend::Api::OpenGL))
|
||||
|
||||
+25
-48
@@ -8,16 +8,8 @@ impl OpenCADStudio {
|
||||
self.pending_startup_modals
|
||||
.push_back(ModalKind::AssocPrompt);
|
||||
}
|
||||
// Automation sessions (#1349): once control traffic has arrived (or a
|
||||
// web host opted in at boot) while control is enabled, the donation
|
||||
// prompt is suppressed — a modal would block every automated
|
||||
// operation until a client closed it by hand.
|
||||
if self.donation_prompt_version != env!("OCS_APP_VERSION")
|
||||
&& !(self.control.enabled && self.control.automation_seen)
|
||||
{
|
||||
self.pending_startup_modals
|
||||
.push_back(ModalKind::DonationPrompt);
|
||||
}
|
||||
// OneBSpace (OneCAD Draft): the donation prompt was removed —
|
||||
// air-gapped build, no fundraising UI at startup.
|
||||
self.show_next_startup_modal();
|
||||
}
|
||||
|
||||
@@ -200,47 +192,32 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn donation_prompt_persists_once_per_version() {
|
||||
fn donation_prompt_is_no_longer_queued() {
|
||||
// OneBSpace (OneCAD Draft): the donation prompt was removed; startup
|
||||
// must never queue it, regardless of the stored prompt version.
|
||||
let mut app = OpenCADStudio::new_for_test();
|
||||
// Older settings have no donation version; headless construction never prompts.
|
||||
app.apply_config(serde_json::from_str::<AppConfig>("{}").unwrap());
|
||||
assert!(app.active_modal.is_none());
|
||||
assert!(app.pending_startup_modals.is_empty());
|
||||
app.default_assoc_prompted = true;
|
||||
app.queue_startup_prompts();
|
||||
assert_eq!(app.active_modal, Some(ModalKind::DonationPrompt));
|
||||
assert!(app.donation_prompt_version.is_empty());
|
||||
|
||||
let _ = app.update(Message::ModalContentResized(iced::Size::new(540.0, 280.0)));
|
||||
let saved = serde_json::to_string(&app.current_config()).unwrap();
|
||||
let _ = app.update(Message::CloseModal);
|
||||
assert!(app.active_modal.is_none());
|
||||
assert!(app.pending_startup_modals.is_empty());
|
||||
|
||||
let mut restarted = OpenCADStudio::new_for_test();
|
||||
restarted.apply_config(serde_json::from_str(&saved).unwrap());
|
||||
restarted.queue_startup_prompts();
|
||||
assert_eq!(restarted.donation_prompt_version, env!("OCS_APP_VERSION"));
|
||||
assert!(restarted.active_modal.is_none());
|
||||
|
||||
restarted.donation_prompt_version = "previous-release".to_string();
|
||||
restarted.queue_startup_prompts();
|
||||
assert_eq!(restarted.active_modal, Some(ModalKind::DonationPrompt));
|
||||
let _ = restarted.update(Message::CommandEscape);
|
||||
assert!(restarted.active_modal.is_none());
|
||||
assert_eq!(restarted.donation_prompt_version, env!("OCS_APP_VERSION"));
|
||||
let _ = restarted.update(Message::Noop);
|
||||
assert!(restarted.active_modal.is_none());
|
||||
app.donation_prompt_version = "previous-release".to_string();
|
||||
app.queue_startup_prompts();
|
||||
assert!(app.active_modal.is_none());
|
||||
assert!(app.pending_startup_modals.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn automation_sessions_skip_the_donation_prompt() {
|
||||
fn automation_sessions_drop_queued_startup_prompts() {
|
||||
// OneBSpace (OneCAD Draft): startup no longer queues the donation
|
||||
// prompt; seed one manually to exercise the automation drop guard.
|
||||
// First control contact drops a still-queued donation prompt and
|
||||
// stops later queueing while control stays enabled (#1349).
|
||||
let mut app = OpenCADStudio::new_for_test();
|
||||
app.default_assoc_prompted = true;
|
||||
app.queue_startup_prompts();
|
||||
assert_eq!(app.active_modal, Some(ModalKind::DonationPrompt));
|
||||
let _ = app.update(Message::CloseModal);
|
||||
app.donation_prompt_version = "previous-release".to_string();
|
||||
app.pending_startup_modals
|
||||
.push_back(ModalKind::DonationPrompt);
|
||||
@@ -248,6 +225,12 @@ mod tests {
|
||||
assert!(app.pending_startup_modals.is_empty());
|
||||
app.queue_startup_prompts();
|
||||
assert_ne!(app.active_modal, Some(ModalKind::DonationPrompt));
|
||||
app.pending_startup_modals
|
||||
.push_back(ModalKind::DonationPrompt);
|
||||
let _ = app.control_request(serde_json::json!({"op":"state"}));
|
||||
assert!(app.pending_startup_modals.is_empty());
|
||||
app.queue_startup_prompts();
|
||||
assert_ne!(app.active_modal, Some(ModalKind::DonationPrompt));
|
||||
|
||||
// A still-queued (not yet shown) prompt is dropped on first contact.
|
||||
let mut queued = OpenCADStudio::new_for_test();
|
||||
@@ -261,11 +244,12 @@ mod tests {
|
||||
assert_ne!(queued.active_modal, Some(ModalKind::DonationPrompt));
|
||||
|
||||
// A prompt already on screen is left for its reader; clients close
|
||||
// it themselves, and a session with no control traffic still prompts.
|
||||
// it themselves. OneBSpace (OneCAD Draft): with no control traffic a
|
||||
// session never sees the donation prompt anymore.
|
||||
let mut human = OpenCADStudio::new_for_test();
|
||||
human.default_assoc_prompted = true;
|
||||
human.queue_startup_prompts();
|
||||
assert_eq!(human.active_modal, Some(ModalKind::DonationPrompt));
|
||||
assert_ne!(human.active_modal, Some(ModalKind::DonationPrompt));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -282,16 +266,9 @@ mod tests {
|
||||
)));
|
||||
assert_eq!(app.active_modal, Some(ModalKind::AssocPrompt));
|
||||
let _ = app.update(Message::AssocPromptNo);
|
||||
assert_eq!(app.active_modal, Some(ModalKind::DonationPrompt));
|
||||
|
||||
// A file-recovery dialog may interrupt startup before the first frame.
|
||||
app.active_modal = Some(ModalKind::Recovery);
|
||||
let _ = app.update(Message::CloseModal);
|
||||
assert_eq!(app.active_modal, Some(ModalKind::DonationPrompt));
|
||||
assert!(app.donation_prompt_version.is_empty());
|
||||
let _ = app.update(Message::ModalContentResized(iced::Size::new(540.0, 280.0)));
|
||||
assert_eq!(app.donation_prompt_version, env!("OCS_APP_VERSION"));
|
||||
let _ = app.update(Message::CloseModal);
|
||||
// OneBSpace (OneCAD Draft): the donation prompt is gone; the update
|
||||
// notice queued by the (manually delivered) check result still waits
|
||||
// its turn behind the association prompt.
|
||||
assert_eq!(app.active_modal, Some(ModalKind::UpdateNotice));
|
||||
let _ = app.update(Message::UpdateNoticeClose);
|
||||
assert!(app.active_modal.is_none());
|
||||
|
||||
@@ -3649,7 +3649,7 @@ impl OpenCADStudio {
|
||||
.map(|name| name.to_string_lossy().into_owned())
|
||||
.unwrap_or_else(|| outcome.path.display().to_string());
|
||||
self.command_line.push_error_once(
|
||||
crate::tf!("Save stopped: \"{file_name}\" changed outside Open CAD Studio.")
|
||||
crate::tf!("Save stopped: \"{file_name}\" changed outside OneCAD Draft.")
|
||||
.as_ref(),
|
||||
);
|
||||
self.pending_external_change = Some(crate::app::PendingExternalChange {
|
||||
|
||||
@@ -11003,9 +11003,10 @@ impl OpenCADStudio {
|
||||
Task::none()
|
||||
}
|
||||
Message::DonationPromptDonate => {
|
||||
// OneBSpace (OneCAD Draft): donations disabled — air-gapped
|
||||
// build; the prompt is never queued, the button is inert.
|
||||
self.close_active_modal();
|
||||
self.dispatch_view("DONATE", self.active_tab)
|
||||
.unwrap_or_else(Task::none)
|
||||
Task::none()
|
||||
}
|
||||
Message::UpdateNoticeClose => {
|
||||
self.close_active_modal();
|
||||
|
||||
+20
-206
@@ -3669,7 +3669,7 @@ fn start_page_content<'a>(
|
||||
action_width_out: std::sync::Arc<std::sync::atomic::AtomicU32>,
|
||||
active: super::StartSection,
|
||||
) -> Element<'a, Message> {
|
||||
let headline = text("Open CAD Studio").size(40).style(start_primary_style);
|
||||
let headline = text("OneCAD Draft").size(40).style(start_primary_style); // OneBSpace (OneCAD Draft): rebranded wordmark
|
||||
|
||||
// Plain outlined button (Open / New / Help / Contribute).
|
||||
let outline_btn = |label: String, msg: Message| {
|
||||
@@ -3695,23 +3695,8 @@ fn start_page_content<'a>(
|
||||
})
|
||||
};
|
||||
|
||||
// Donate — the prominent call-to-action, using the theme's danger role.
|
||||
let donate_btn = {
|
||||
button(
|
||||
row![
|
||||
crate::ui::icons::themed_danger_text(crate::ui::icons::HEART, 14.0),
|
||||
text(crate::tr!("start", "donate")).size(14),
|
||||
]
|
||||
.spacing(5)
|
||||
.align_y(iced::Center),
|
||||
)
|
||||
.on_press(Message::RibbonToolClick {
|
||||
tool_id: "DONATE".to_string(),
|
||||
event: crate::modules::ModuleEvent::Command("DONATE".to_string()),
|
||||
})
|
||||
.padding([10, 22])
|
||||
.style(|theme: &Theme, status| start_action_shape(button::danger(theme, status)))
|
||||
};
|
||||
// OneBSpace (OneCAD Draft): the donation call-to-action was removed —
|
||||
// air-gapped build, no external fundraising links.
|
||||
|
||||
let primary_row = WrapFlow::new(vec![
|
||||
outline_btn(crate::tr!("start", "new-drawing"), Message::TabNew).into(),
|
||||
@@ -3725,7 +3710,6 @@ fn start_page_content<'a>(
|
||||
)
|
||||
.into(),
|
||||
outline_btn(crate::tr!("start", "open-file"), Message::OpenFile).into(),
|
||||
donate_btn.into(),
|
||||
])
|
||||
.spacing_x(12.0)
|
||||
.row_h(48.0)
|
||||
@@ -3745,90 +3729,15 @@ fn start_page_content<'a>(
|
||||
];
|
||||
secondary_items
|
||||
.push(outline_btn(crate::tr!("action", "plugins"), Message::PluginManagerOpen).into());
|
||||
// The web build is already in the browser, so only the desktop offers a
|
||||
// link to the web version.
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
// Filled with the active theme's primary colour.
|
||||
secondary_items.push(
|
||||
button(text(crate::t!("OCS Web")).size(14))
|
||||
.on_press(Message::RibbonToolClick {
|
||||
tool_id: "WEBVERSION".to_string(),
|
||||
event: crate::modules::ModuleEvent::Command("WEBVERSION".to_string()),
|
||||
})
|
||||
.padding([10, 22])
|
||||
.style(|theme: &Theme, status| start_action_shape(button::primary(theme, status)))
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
secondary_items.push(
|
||||
button(text(crate::t!("OCS Desktop")).size(14))
|
||||
.on_press(Message::OpenUrl(
|
||||
"https://github.com/HakanSeven12/OpenCADStudio/releases/latest".to_string(),
|
||||
))
|
||||
.padding([10, 22])
|
||||
.style(|theme: &Theme, status| start_action_shape(button::primary(theme, status)))
|
||||
.into(),
|
||||
);
|
||||
// OneBSpace (OneCAD Draft): the "OCS Web" / "OCS Desktop" cross-promotion
|
||||
// buttons were removed — no external download or website links.
|
||||
let secondary_row = WrapFlow::new(secondary_items)
|
||||
.spacing_x(12.0)
|
||||
.row_h(44.0)
|
||||
.report_natural_width(action_width_out.clone());
|
||||
|
||||
let reddit_btn = button(
|
||||
row![
|
||||
iced::widget::svg(iced::widget::svg::Handle::from_memory(include_bytes!(
|
||||
"../../../assets/icons/reddit.svg"
|
||||
)))
|
||||
.width(20)
|
||||
.height(20),
|
||||
text("r/OpenCADStudio").size(14),
|
||||
]
|
||||
.spacing(7)
|
||||
.align_y(iced::Center),
|
||||
)
|
||||
.on_press(Message::OpenUrl(
|
||||
"https://www.reddit.com/r/OpenCADStudio/".to_string(),
|
||||
))
|
||||
.padding([10, 22])
|
||||
.style(|theme: &Theme, status| {
|
||||
let palette = theme.palette();
|
||||
let pair = match status {
|
||||
button::Status::Hovered => palette.background.strong,
|
||||
_ => palette.background.weak,
|
||||
};
|
||||
start_action_shape(button::Style {
|
||||
background: Some(Background::Color(pair.color)),
|
||||
text_color: pair.text,
|
||||
border: Border {
|
||||
color: Color::from_rgb8(255, 69, 0),
|
||||
width: 1.0,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
})
|
||||
});
|
||||
|
||||
let sponsors = column![
|
||||
text(crate::tr!("start", "sponsors")).size(15),
|
||||
mouse_area(
|
||||
container(
|
||||
iced::widget::svg(iced::widget::svg::Handle::from_memory(include_bytes!(
|
||||
"../../../assets/sponsors/openaec-logo-dark-on-light.svg"
|
||||
)))
|
||||
.width(Fill)
|
||||
.height(iced::Length::Fixed(120.0))
|
||||
.content_fit(iced::ContentFit::Contain),
|
||||
)
|
||||
.width(Fill.max(300.0)),
|
||||
)
|
||||
.interaction(iced::mouse::Interaction::Pointer)
|
||||
.on_press(Message::OpenUrl("https://open-aec.com/".to_string())),
|
||||
]
|
||||
.spacing(10)
|
||||
.align_x(iced::alignment::Horizontal::Center)
|
||||
.width(Fill);
|
||||
// OneBSpace (OneCAD Draft): the community Reddit link and the Open-AEC
|
||||
// sponsor block were removed — no external links in the Start page.
|
||||
|
||||
let content = column![
|
||||
Space::new().height(iced::Length::Fixed(28.0)),
|
||||
@@ -3837,10 +3746,6 @@ fn start_page_content<'a>(
|
||||
container(primary_row).center_x(Fill),
|
||||
Space::new().height(iced::Length::Fixed(10.0)),
|
||||
container(secondary_row).center_x(Fill),
|
||||
Space::new().height(iced::Length::Fixed(10.0)),
|
||||
container(reddit_btn).center_x(Fill),
|
||||
Space::new().height(iced::Length::Fixed(20.0)),
|
||||
sponsors,
|
||||
Space::new().height(iced::Length::Fixed(52.0)),
|
||||
]
|
||||
.spacing(0)
|
||||
@@ -3908,8 +3813,9 @@ fn start_page_content<'a>(
|
||||
);
|
||||
let welcome = container(content).width(Fill).height(Fill);
|
||||
|
||||
// Tutorial-videos rail: the official playlist, fetched at boot (cached on
|
||||
// disk) — thumbnail card + title per video, click opens the browser.
|
||||
// Tutorial-videos rail: local listing only (cached on disk / bundled
|
||||
// videos.json) — thumbnail card + title per video; OneBSpace (OneCAD
|
||||
// Draft): no click-through, cards are informational (air-gapped build).
|
||||
let videos_panel: Element<'a, Message> = {
|
||||
// Derive the 16:9 cover box from the actual shared list width so the
|
||||
// whole thumbnail remains visible when that width changes.
|
||||
@@ -3946,11 +3852,9 @@ fn start_page_content<'a>(
|
||||
);
|
||||
}
|
||||
card = card.push(text(v.title.clone()).size(12).style(start_muted_style));
|
||||
list = list.push(
|
||||
mouse_area(card)
|
||||
.interaction(iced::mouse::Interaction::Pointer)
|
||||
.on_press(Message::OpenUrl(crate::videos::watch_url(&v.id))),
|
||||
);
|
||||
// OneBSpace (OneCAD Draft): cards are informational only — no
|
||||
// click-through to YouTube (air-gapped build).
|
||||
list = list.push(card);
|
||||
}
|
||||
if videos.is_empty() {
|
||||
let note = if videos_loading {
|
||||
@@ -3960,32 +3864,7 @@ fn start_page_content<'a>(
|
||||
};
|
||||
list = list.push(text(note).size(12).style(start_muted_style));
|
||||
}
|
||||
let playlist_btn = mouse_area(
|
||||
container(text(crate::tr!("start", "open-playlist")).size(12))
|
||||
.padding([6, 10])
|
||||
.width(Fill)
|
||||
.center_x(Fill)
|
||||
.style(|theme: &Theme| {
|
||||
let pair = theme.palette().danger.base;
|
||||
container::Style {
|
||||
background: Some(Background::Color(pair.color)),
|
||||
border: Border {
|
||||
color: Color::TRANSPARENT,
|
||||
width: 0.0,
|
||||
radius: 6.0.into(),
|
||||
},
|
||||
text_color: Some(pair.text),
|
||||
..Default::default()
|
||||
}
|
||||
}),
|
||||
)
|
||||
.interaction(iced::mouse::Interaction::Pointer)
|
||||
.on_press(Message::OpenUrl(crate::videos::PLAYLIST_URL.to_string()));
|
||||
container(column![
|
||||
iced::widget::scrollable(list).height(Fill),
|
||||
Space::new().height(iced::Length::Fixed(12.0)),
|
||||
playlist_btn,
|
||||
])
|
||||
container(column![iced::widget::scrollable(list).height(Fill)])
|
||||
.width(match start_layout {
|
||||
StartLayout::AllPanels => iced::Length::Fixed(panel_w),
|
||||
StartLayout::WithoutVideos
|
||||
@@ -4055,11 +3934,7 @@ fn start_page_content<'a>(
|
||||
..Default::default()
|
||||
}
|
||||
});
|
||||
list = list.push(
|
||||
mouse_area(card)
|
||||
.interaction(iced::mouse::Interaction::Pointer)
|
||||
.on_press(Message::OpenUrl(discussion.url.clone())),
|
||||
);
|
||||
list = list.push(card);
|
||||
}
|
||||
if discussions.is_empty() {
|
||||
let note = if discussions_loading {
|
||||
@@ -4069,34 +3944,7 @@ fn start_page_content<'a>(
|
||||
};
|
||||
list = list.push(text(note).size(12).style(start_muted_style));
|
||||
}
|
||||
let open_btn = mouse_area(
|
||||
container(text(crate::tr!("start", "open-discussions")).size(12))
|
||||
.padding([6, 10])
|
||||
.width(Fill)
|
||||
.center_x(Fill)
|
||||
.style(|theme: &Theme| {
|
||||
let pair = theme.palette().primary.base;
|
||||
container::Style {
|
||||
background: Some(Background::Color(pair.color)),
|
||||
border: Border {
|
||||
color: Color::TRANSPARENT,
|
||||
width: 0.0,
|
||||
radius: 6.0.into(),
|
||||
},
|
||||
text_color: Some(pair.text),
|
||||
..Default::default()
|
||||
}
|
||||
}),
|
||||
)
|
||||
.interaction(iced::mouse::Interaction::Pointer)
|
||||
.on_press(Message::OpenUrl(
|
||||
crate::discussions::DISCUSSIONS_URL.to_string(),
|
||||
));
|
||||
container(column![
|
||||
iced::widget::scrollable(list).height(Fill),
|
||||
Space::new().height(iced::Length::Fixed(12.0)),
|
||||
open_btn,
|
||||
])
|
||||
container(column![iced::widget::scrollable(list).height(Fill)])
|
||||
.width(match start_layout {
|
||||
StartLayout::AllPanels | StartLayout::WithoutVideos => iced::Length::Fixed(panel_w),
|
||||
StartLayout::WithoutVideosAndDiscussions
|
||||
@@ -4120,9 +3968,9 @@ fn start_page_content<'a>(
|
||||
.into()
|
||||
};
|
||||
|
||||
// Right rail: Patreon supporters, fetched at boot. When the list is empty
|
||||
// (no token configured / offline) only the "Support on Patreon" button
|
||||
// shows, so the rail always invites support.
|
||||
// OneBSpace (OneCAD Draft): right rail shows the local supporters list
|
||||
// only — the Patreon fetch and the "Support on Patreon" button were
|
||||
// removed (air-gapped build, no external links).
|
||||
let supporters: Element<'a, Message> = {
|
||||
let mut list = column![
|
||||
text(crate::tr!("start", "supporters")).size(15),
|
||||
@@ -4146,41 +3994,7 @@ fn start_page_content<'a>(
|
||||
.spacing(6),
|
||||
);
|
||||
}
|
||||
let support_btn = mouse_area(
|
||||
container(
|
||||
iced::widget::row![
|
||||
crate::ui::icons::themed_danger_text(crate::ui::icons::HEART, 13.0),
|
||||
text(crate::tr!("start", "support-on-patreon")).size(12),
|
||||
]
|
||||
.spacing(6)
|
||||
.align_y(iced::Center),
|
||||
)
|
||||
.padding([6, 10])
|
||||
.width(Fill)
|
||||
.center_x(Fill)
|
||||
.style(|theme: &Theme| {
|
||||
let pair = theme.palette().danger.base;
|
||||
container::Style {
|
||||
background: Some(Background::Color(pair.color)),
|
||||
border: Border {
|
||||
color: Color::TRANSPARENT,
|
||||
width: 0.0,
|
||||
radius: 6.0.into(),
|
||||
},
|
||||
text_color: Some(pair.text),
|
||||
..Default::default()
|
||||
}
|
||||
}),
|
||||
)
|
||||
.interaction(iced::mouse::Interaction::Pointer)
|
||||
.on_press(Message::OpenUrl(
|
||||
"https://patreon.com/HakanSeven12".to_string(),
|
||||
));
|
||||
container(column![
|
||||
iced::widget::scrollable(list).height(Fill),
|
||||
Space::new().height(iced::Length::Fixed(12.0)),
|
||||
support_btn,
|
||||
])
|
||||
container(column![iced::widget::scrollable(list).height(Fill)])
|
||||
.width(match start_layout {
|
||||
StartLayout::AllPanels
|
||||
| StartLayout::WithoutVideos
|
||||
|
||||
@@ -2589,10 +2589,10 @@ fn donation_dialog_window(sizing: crate::ui::modal::ModalSizing) -> Element<'sta
|
||||
fn default_assoc_dialog_window(sizing: crate::ui::modal::ModalSizing) -> Element<'static, Message> {
|
||||
container(
|
||||
column![
|
||||
text(t!("Make Open CAD Studio your default CAD app?"))
|
||||
text(t!("Make OneCAD Draft your default CAD app?")) /* OneBSpace (OneCAD Draft): rebranded */
|
||||
.size(15),
|
||||
iced::widget::Space::new().height(10),
|
||||
text(t!("Open .dwg and .dxf drawings in Open CAD Studio by default. You can change this later in your system settings."))
|
||||
text(t!("Open .dwg and .dxf drawings in OneCAD Draft by default. You can change this later in your system settings.")) /* OneBSpace (OneCAD Draft): rebranded */
|
||||
.size(12)
|
||||
.style(dialog_muted_text_style),
|
||||
iced::widget::Space::new().height(22),
|
||||
|
||||
Reference in new issue
Block a user