[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:
Z User committed 2026-10-18 21:25:27 +00:00
1 parent c9e763006e
commit 193f2ae9ab
57 files changed
+760 -1091

No files matched your search

+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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());
+1 -1
View File
@@ -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 {
+3 -2
View File
@@ -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
View File
@@ -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
+2 -2
View File
@@ -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),