Show donation request once per app version

This commit is contained in:
Hakan Seven committed 2026-09-06 11:44:38 +03:00
1 parent 1b0a42a35c
commit 2c83ae2736
28 files changed
+332 -24

No files matched your search

+6
View File
@@ -90,6 +90,12 @@ start =
.browser-storage = تخزين المتصفح
.keep-recent-files = الاحتفاظ بالملفات الأخيرة
donation =
.title = طلب تبرع
.heading = تبرّع لـ Open CAD Studio
.body = يحتاج Open CAD Studio إلى مساعدتك! تموّل التبرعات أعمال التطوير والبنية التحتية الضرورية لاستمرار Open CAD Studio.
.decline = لا، شكرًا
modal =
.about = حول
.keyboard-shortcuts = اختصارات لوحة المفاتيح
+6
View File
@@ -90,6 +90,12 @@ start =
.browser-storage = Хранилище на браузъра
.keep-recent-files = Пази скорошните файлове
donation =
.title = Призив за дарение
.heading = Дарете за Open CAD Studio
.body = Open CAD Studio се нуждае от вашата помощ! Даренията финансират разработката и инфраструктурата, важни за продължаващото съществуване на Open CAD Studio.
.decline = Не, благодаря
modal =
.about = Относно
.keyboard-shortcuts = Клавишни комбинации
+6
View File
@@ -90,6 +90,12 @@ start =
.browser-storage = Úložiště prohlížeče
.keep-recent-files = Uchovávat nedávné soubory
donation =
.title = Žádost o dar
.heading = Přispějte na Open CAD Studio
.body = Open CAD Studio potřebuje vaši pomoc! Dary financují vývoj a infrastrukturu důležité pro další existenci Open CAD Studio.
.decline = Ne, děkuji
modal =
.about = O aplikaci
.keyboard-shortcuts = Klávesové zkratky
+6
View File
@@ -90,6 +90,12 @@ start =
.browser-storage = Browserspeicher
.keep-recent-files = Zuletzt verwendete Dateien behalten
donation =
.title = Spendenaufruf
.heading = Für Open CAD Studio spenden
.body = Open CAD Studio braucht Ihre Hilfe! Spenden finanzieren die Entwicklung und Infrastruktur, die für den Fortbestand von Open CAD Studio wichtig sind.
.decline = Nein, danke
modal =
.about = Über
.keyboard-shortcuts = Tastenkombinationen
+6
View File
@@ -90,6 +90,12 @@ start =
.browser-storage = Αποθηκευτικός χώρος προγράμματος περιήγησης
.keep-recent-files = Διατήρηση πρόσφατων αρχείων
donation =
.title = Έκκληση για δωρεά
.heading = Κάντε δωρεά στο Open CAD Studio
.body = Το Open CAD Studio χρειάζεται τη βοήθειά σας! Οι δωρεές χρηματοδοτούν την ανάπτυξη και τις υποδομές που είναι σημαντικές για τη συνέχιση της ύπαρξης του Open CAD Studio.
.decline = Όχι, ευχαριστώ
modal =
.about = Σχετικά
.keyboard-shortcuts = Συντομεύσεις πληκτρολογίου
+6
View File
@@ -90,6 +90,12 @@ start =
.browser-storage = Browser storage
.keep-recent-files = Keep recent files
donation =
.title = Request for Donation
.heading = Donate to Open CAD Studio
.body = Open CAD Studio needs your help! Donations fund development and infrastructure important for Open CAD Studio's continued existence.
.decline = No Thanks
modal =
.about = About
.keyboard-shortcuts = Keyboard Shortcuts
+6
View File
@@ -90,6 +90,12 @@ start =
.browser-storage = Almacenamiento del navegador
.keep-recent-files = Conservar archivos recientes
donation =
.title = Solicitud de donación
.heading = Dona a Open CAD Studio
.body = ¡Open CAD Studio necesita tu ayuda! Las donaciones financian el desarrollo y la infraestructura que son importantes para que Open CAD Studio siga existiendo.
.decline = No, gracias
modal =
.about = Acerca de
.keyboard-shortcuts = Métodos abreviados de teclado
+6
View File
@@ -90,6 +90,12 @@ start =
.browser-storage = Selaimen tallennustila
.keep-recent-files = Säilytä viimeisimmät tiedostot
donation =
.title = Lahjoituspyyntö
.heading = Lahjoita Open CAD Studiolle
.body = Open CAD Studio tarvitsee apuasi! Lahjoituksilla rahoitetaan kehitystyötä ja infrastruktuuria, jotka ovat tärkeitä Open CAD Studion toiminnan jatkumiselle.
.decline = Ei kiitos
modal =
.about = Tietoja
.keyboard-shortcuts = Pikanäppäimet
+6
View File
@@ -90,6 +90,12 @@ start =
.browser-storage = Stockage du navigateur
.keep-recent-files = Conserver les fichiers récents
donation =
.title = Appel aux dons
.heading = Faire un don à Open CAD Studio
.body = Open CAD Studio a besoin de votre aide ! Les dons financent le développement et l’infrastructure essentiels à la pérennité d’Open CAD Studio.
.decline = Non merci
modal =
.about = À propos
.keyboard-shortcuts = Raccourcis clavier
+6
View File
@@ -90,6 +90,12 @@ start =
.browser-storage = ब्राउज़र संग्रहण
.keep-recent-files = हाल की फ़ाइलें रखें
donation =
.title = दान का अनुरोध
.heading = Open CAD Studio को दान दें
.body = Open CAD Studio को आपकी मदद चाहिए! दान से विकास और बुनियादी ढाँचे का खर्च पूरा होता है, जो Open CAD Studio के अस्तित्व को बनाए रखने के लिए महत्वपूर्ण हैं।
.decline = नहीं, धन्यवाद
modal =
.about = परिचय
.keyboard-shortcuts = कीबोर्ड शॉर्टकट
+6
View File
@@ -90,6 +90,12 @@ start =
.browser-storage = Böngésző tárhelye
.keep-recent-files = Legutóbbi fájlok megőrzése
donation =
.title = Adománykérés
.heading = Támogassa az Open CAD Studiót
.body = Az Open CAD Studiónak szüksége van a segítségére! Az adományok az Open CAD Studio fennmaradásához fontos fejlesztést és infrastruktúrát finanszírozzák.
.decline = Nem, köszönöm
modal =
.about = Névjegy
.keyboard-shortcuts = Billentyűparancsok
+6
View File
@@ -90,6 +90,12 @@ start =
.browser-storage = Memoria del browser
.keep-recent-files = Conserva i file recenti
donation =
.title = Richiesta di donazione
.heading = Dona a Open CAD Studio
.body = Open CAD Studio ha bisogno del tuo aiuto! Le donazioni finanziano lo sviluppo e l’infrastruttura importanti per la continuità di Open CAD Studio.
.decline = No, grazie
modal =
.about = Informazioni
.keyboard-shortcuts = Scorciatoie da tastiera
+6
View File
@@ -90,6 +90,12 @@ start =
.browser-storage = ブラウザーストレージ
.keep-recent-files = 最近使ったファイルを保持
donation =
.title = 寄付のお願い
.heading = Open CAD Studio に寄付する
.body = Open CAD Studio は皆さまの支援を必要としています!寄付は、Open CAD Studio の存続に重要な開発とインフラの資金に充てられます。
.decline = 今はしない
modal =
.about = バージョン情報
.keyboard-shortcuts = キーボードショートカット
+6
View File
@@ -90,6 +90,12 @@ start =
.browser-storage = 브라우저 저장소
.keep-recent-files = 최근 파일 유지
donation =
.title = 기부 요청
.heading = Open CAD Studio에 기부하기
.body = Open CAD Studio는 여러분의 도움이 필요합니다! 기부금은 Open CAD Studio의 지속적인 운영에 중요한 개발과 인프라 비용을 지원합니다.
.decline = 괜찮습니다
modal =
.about = 정보
.keyboard-shortcuts = 키보드 단축키
+6
View File
@@ -90,6 +90,12 @@ start =
.browser-storage = Browseropslag
.keep-recent-files = Recente bestanden bewaren
donation =
.title = Verzoek om een donatie
.heading = Doneer aan Open CAD Studio
.body = Open CAD Studio heeft uw hulp nodig! Donaties financieren de ontwikkeling en infrastructuur die belangrijk zijn voor het voortbestaan van Open CAD Studio.
.decline = Nee, bedankt
modal =
.about = Over
.keyboard-shortcuts = Sneltoetsen
+6
View File
@@ -90,6 +90,12 @@ start =
.browser-storage = Pamięć przeglądarki
.keep-recent-files = Zachowuj ostatnie pliki
donation =
.title = Prośba o darowiznę
.heading = Wesprzyj Open CAD Studio
.body = Open CAD Studio potrzebuje Twojej pomocy! Darowizny finansują rozwój i infrastrukturę niezbędne do dalszego istnienia Open CAD Studio.
.decline = Nie, dziękuję
modal =
.about = Informacje
.keyboard-shortcuts = Skróty klawiaturowe
+6
View File
@@ -90,6 +90,12 @@ start =
.browser-storage = Armazenamento do navegador
.keep-recent-files = Manter arquivos recentes
donation =
.title = Pedido de doação
.heading = Doe para o Open CAD Studio
.body = O Open CAD Studio precisa da sua ajuda! As doações financiam o desenvolvimento e a infraestrutura importantes para a continuidade do Open CAD Studio.
.decline = Não, obrigado
modal =
.about = Sobre
.keyboard-shortcuts = Atalhos de teclado
+6
View File
@@ -90,6 +90,12 @@ start =
.browser-storage = Хранилище браузера
.keep-recent-files = Хранить недавние файлы
donation =
.title = Просьба о пожертвовании
.heading = Поддержите Open CAD Studio
.body = Open CAD Studio нужна ваша помощь! Пожертвования финансируют разработку и инфраструктуру, важные для дальнейшего существования Open CAD Studio.
.decline = Нет, спасибо
modal =
.about = О программе
.keyboard-shortcuts = Настройки клавиатуры
+6
View File
@@ -90,6 +90,12 @@ start =
.browser-storage = Tarayıcı depolama alanı
.keep-recent-files = Son dosyaları sakla
donation =
.title = Bağış Talebi
.heading = Open CAD Studio'ya Bağış Yapın
.body = Open CAD Studio'nun yardımınıza ihtiyacı var! Bağışlar, Open CAD Studio'nun varlığını sürdürebilmesi için önemli olan geliştirme çalışmalarını ve altyapıyı finanse eder.
.decline = Hayır, Teşekkürler
modal =
.about = Hakkında
.keyboard-shortcuts = Klavye Kısayolları
+6
View File
@@ -90,6 +90,12 @@ start =
.browser-storage = 浏览器存储
.keep-recent-files = 保留最近文件
donation =
.title = 捐款请求
.heading = 向 Open CAD Studio 捐款
.body = Open CAD Studio 需要您的帮助!捐款将用于资助对 Open CAD Studio 持续发展至关重要的开发工作和基础设施。
.decline = 不,谢谢
modal =
.about = 关于
.keyboard-shortcuts = 键盘快捷键
+6
View File
@@ -90,6 +90,12 @@ start =
.browser-storage = 瀏覽器儲存空間
.keep-recent-files = 保留最近檔案
donation =
.title = 捐款請求
.heading = 捐款給 Open CAD Studio
.body = Open CAD Studio 需要您的協助!捐款將用於資助對 Open CAD Studio 持續發展至關重要的開發工作與基礎設施。
.decline = 不用,謝謝
modal =
.about = 關於
.keyboard-shortcuts = 鍵盤快速鍵
+10 -14
View File
@@ -24,6 +24,7 @@ mod presspull_ops;
mod recent;
pub(crate) mod settings;
mod shortcuts;
mod startup;
mod style_ops;
mod text_inline;
mod tolerance_dialog;
@@ -691,6 +692,7 @@ pub(super) struct OpenCADStudio {
/// The open in-canvas modal dialog, if any (Plan B: shared overlay instead
/// of OS windows).
active_modal: Option<ModalKind>,
pending_startup_modals: std::collections::VecDeque<ModalKind>,
/// Plot modal geometry preserved while the Plot Style editor is open as
/// a child dialog. None means Plotstyle was opened directly (e.g. command).
plotstyle_parent_plot_geometry: Option<(iced::Vector, iced::Vector)>,
@@ -795,13 +797,9 @@ pub(super) struct OpenCADStudio {
/// Tracked separately from the PDSIZE sign so a size of 0 (sign-less) still
/// remembers which radio is active.
point_size_relative: bool,
/// New-release notification window — opened on startup when the
/// GitHub releases API reports a newer version than this build.
/// First-launch "make Open CAD Studio the default for .dwg/.dxf?" prompt
/// window. Shown once, gated on `default_assoc_prompted`.
/// Whether the one-time default-association prompt has already been shown.
/// Persisted via [`settings::UserSettings`] so it survives restarts.
/// Whether the default-association prompt has been answered.
default_assoc_prompted: bool,
donation_prompt_version: String,
/// Read-only session (`--read-only`): editing is allowed but every save
/// path is refused. Set once at boot from the CLI config.
read_only: bool,
@@ -1663,6 +1661,7 @@ pub enum ModalKind {
Shortcuts,
PluginManager,
UpdateNotice,
DonationPrompt,
Layers,
LayerStateManager,
LayerTranslator,
@@ -2914,6 +2913,7 @@ pub enum Message {
UpdateCheckResult(Option<crate::io::update_check::UpdateInfo>),
/// User dismissed the update-notice window.
UpdateNoticeClose,
DonationPromptDonate,
/// First-launch default-association prompt: user accepted — register this
/// app as the default handler for .dwg / .dxf.
AssocPromptYes,
@@ -3421,6 +3421,7 @@ impl OpenCADStudio {
color_picker_tab: ColorPickerTab::Index,
recent_colors: Vec::new(),
active_modal: None,
pending_startup_modals: std::collections::VecDeque::new(),
plotstyle_parent_plot_geometry: None,
find_replace: FindReplaceState::default(),
aec_drop_acknowledged: false,
@@ -3461,6 +3462,7 @@ impl OpenCADStudio {
point_size_buf: String::new(),
point_size_relative: true,
default_assoc_prompted: false,
donation_prompt_version: String::new(),
read_only: false,
update_notice_version: None,
update_notice_body: None,
@@ -3831,13 +3833,7 @@ impl OpenCADStudio {
.map(|line| Task::done(Message::Command(line))),
)
};
// One-time prompt offering to make Open CAD Studio the default app for
// .dwg / .dxf. Shown only on the first launch that hasn't answered it
// yet; the flag is persisted so we never ask twice.
let assoc_prompt: Task<Message> = Task::none();
if !s.default_assoc_prompted {
s.active_modal = Some(ModalKind::AssocPrompt);
}
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(
@@ -3900,7 +3896,6 @@ impl OpenCADStudio {
focus_cmd,
cli_open,
script,
assoc_prompt,
patrons_fetch,
videos_fetch,
discussions_fetch,
@@ -3916,6 +3911,7 @@ impl OpenCADStudio {
fn boot_web() -> (Self, Task<Message>) {
#[cfg_attr(target_arch = "wasm32", allow(unused_mut))]
let mut s = Self::new();
s.queue_startup_prompts();
let focus = s.focus_cmd_input();
let primary_font = crate::scene::text::web_font::preload_language(
&crate::i18n::active_language_tag(),
+4 -1
View File
@@ -90,7 +90,7 @@ const SNAP_ORDER: &[SnapType] = &[
// persisted set. (#121)
];
/// `$OSMODE` bit for each running object-snap mode (standard AutoCAD bitmask).
/// `$OSMODE` bit for each running object-snap mode.
/// `None` for OCS-only snaps (Grid, ObjectPick) that have no standard bit.
fn snap_bit(s: SnapType) -> Option<i32> {
Some(match s {
@@ -179,6 +179,8 @@ pub struct UserSettings {
/// prompt has already been shown. Set once the user answers (either way),
/// so we never nag again on subsequent launches.
pub default_assoc_prompted: bool,
/// App version whose donation prompt has been displayed.
pub donation_prompt_version: String,
/// Ids of plugins the user turned off in the Plugin Manager. Disabled
/// plugins keep their manifest listed but drop their ribbon tab and command
/// dispatch.
@@ -313,6 +315,7 @@ impl Default for UserSettings {
snap_angle_deg: 0.0,
otrack: false,
default_assoc_prompted: false,
donation_prompt_version: String::new(),
disabled_plugins: Vec::new(),
plugin_repos: Vec::new(),
literal_spaces: false,
+108
View File
@@ -0,0 +1,108 @@
use super::{ModalKind, OpenCADStudio};
impl OpenCADStudio {
pub(super) fn queue_startup_prompts(&mut self) {
#[cfg(not(target_arch = "wasm32"))]
if !self.default_assoc_prompted {
self.pending_startup_modals
.push_back(ModalKind::AssocPrompt);
}
if self.donation_prompt_version != env!("OCS_APP_VERSION") {
self.pending_startup_modals
.push_back(ModalKind::DonationPrompt);
}
self.show_next_startup_modal();
}
pub(super) fn show_next_startup_modal(&mut self) {
if self.active_modal.is_none() && self.opening.is_none() && self.pending_opens.is_empty() {
if let Some(&kind) = self.pending_startup_modals.front() {
self.active_modal = Some(kind);
self.reset_modal_geometry();
}
}
}
pub(super) fn mark_startup_modal_shown(&mut self) {
if self.active_modal.is_some()
&& self.active_modal.as_ref() == self.pending_startup_modals.front()
{
self.pending_startup_modals.pop_front();
}
if self.active_modal == Some(ModalKind::DonationPrompt)
&& self.donation_prompt_version != env!("OCS_APP_VERSION")
{
self.donation_prompt_version = env!("OCS_APP_VERSION").to_string();
self.save_config();
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::app::{config::AppConfig, Message};
#[test]
fn donation_prompt_persists_once_per_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());
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());
}
#[test]
fn startup_dialogs_wait_their_turn_and_preserve_unseen_prompts() {
let mut app = OpenCADStudio::new_for_test();
app.apply_config(AppConfig::default());
app.queue_startup_prompts();
assert_eq!(app.active_modal, Some(ModalKind::AssocPrompt));
let _ = app.update(Message::UpdateCheckResult(Some(
crate::io::update_check::UpdateInfo {
version: "next-release".to_string(),
body: String::new(),
},
)));
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);
assert_eq!(app.active_modal, Some(ModalKind::UpdateNotice));
let _ = app.update(Message::UpdateNoticeClose);
assert!(app.active_modal.is_none());
assert!(app.pending_startup_modals.is_empty());
}
}
+2
View File
@@ -370,6 +370,7 @@ impl OpenCADStudio {
snap_angle_deg: self.snap_angle_deg,
otrack: self.snapper.otrack_enabled,
default_assoc_prompted: self.default_assoc_prompted,
donation_prompt_version: self.donation_prompt_version.clone(),
disabled_plugins: {
let mut v: Vec<String> = self.disabled_plugins.iter().cloned().collect();
v.sort();
@@ -432,6 +433,7 @@ impl OpenCADStudio {
// open / tab switch), not app-global, so they are not applied here.
self.snapper.otrack_enabled = s.otrack;
self.default_assoc_prompted = s.default_assoc_prompted;
self.donation_prompt_version = s.donation_prompt_version.clone();
self.disabled_plugins = s.disabled_plugins.iter().cloned().collect();
self.plugin_repos = s.plugin_repos.clone();
self.command_line.literal_spaces = s.literal_spaces;
+12 -5
View File
@@ -124,6 +124,7 @@ impl OpenCADStudio {
/// old OS window did: a style editor discards its staged (un-applied)
/// changes, and the ribbon tool that launched the dialog is de-highlighted.
fn close_active_modal(&mut self) {
self.mark_startup_modal_shown();
use super::ModalKind::*;
// Plot Style opened from PLOT behaves as a child modal.
// Closing it restores the parent Plot dialog instead of returning
@@ -282,6 +283,7 @@ impl OpenCADStudio {
}
}
let task = self.update_inner(msg);
self.show_next_startup_modal();
self.sync_open_command_history();
// Close the document-level first-touch transaction started by
// push_undo_snapshot at this message boundary.
@@ -6429,6 +6431,7 @@ impl OpenCADStudio {
return Task::none();
}
let first_measurement = self.modal_content_size.replace(size).is_none();
self.mark_startup_modal_shown();
if first_measurement {
let initial_width = self.mtext_editor.as_ref().and_then(|editor| {
editor.editing.is_none().then(|| {
@@ -7125,9 +7128,15 @@ impl OpenCADStudio {
};
self.update_notice_version = Some(info.version);
self.update_notice_body = Some(info.body);
self.active_modal = Some(super::ModalKind::UpdateNotice);
self.pending_startup_modals
.push_back(super::ModalKind::UpdateNotice);
Task::none()
}
Message::DonationPromptDonate => {
self.close_active_modal();
self.dispatch_view("DONATE", self.active_tab)
.unwrap_or_else(Task::none)
}
Message::UpdateNoticeClose => {
self.close_active_modal();
Task::none()
@@ -7143,8 +7152,7 @@ impl OpenCADStudio {
Message::AssocPromptYes => {
self.file_assoc_enabled = true;
self.mark_assoc_prompted();
self.active_modal = None;
self.reset_modal_geometry();
self.close_active_modal();
// set_default_app registers the handler first, then makes us the
// default — boot no longer does this automatically.
Task::perform(
@@ -7155,8 +7163,7 @@ impl OpenCADStudio {
Message::AssocPromptNo => {
self.file_assoc_enabled = false;
self.mark_assoc_prompted();
self.active_modal = None;
self.reset_modal_geometry();
self.close_active_modal();
Task::none()
}
Message::AssocResult(result) => {
+41 -4
View File
@@ -17,6 +17,7 @@ impl OpenCADStudio {
Some(K::FindReplace) => crate::tr!("modal", "find-replace"),
Some(K::PluginManager) => crate::tr!("modal", "plugin-manager"),
Some(K::UpdateNotice) => crate::tr!("modal", "update-available"),
Some(K::DonationPrompt) => crate::tr!("donation", "title"),
Some(K::Layers) => crate::tr!("modal", "layer-manager"),
Some(K::LayerStateManager) => crate::tr!("modal", "layer-state-manager"),
Some(K::LayerTranslator) => crate::t!("Layer Translator").into_owned(),
@@ -1300,6 +1301,9 @@ impl OpenCADStudio {
super::super::ModalKind::AssocPrompt => {
automatic_flow(ex, default_assoc_dialog_window)
}
super::super::ModalKind::DonationPrompt => {
sized_flow(ex, 540, 360, donation_dialog_window)
}
super::super::ModalKind::AecDropWarning => {
let src_label = self
.tabs
@@ -1843,10 +1847,43 @@ fn layer_delete_warning_window(
.into()
}
/// First-launch prompt offering to register Open CAD Studio as the default
/// handler for .dwg / .dxf. "Yes" runs the platform association call; "Not now"
/// just dismisses. Either answer flips the persisted `default_assoc_prompted`
/// flag so the dialog never reappears.
fn donation_dialog_window(sizing: crate::ui::modal::ModalSizing) -> Element<'static, Message> {
container(
column![
text(crate::tr!("donation", "heading")).size(18),
row![
text(crate::tr!("donation", "body"))
.size(14)
.width(Fill),
crate::ui::icons::themed(crate::ui::icons::HEART, 52.0),
]
.spacing(20)
.align_y(iced::Center),
row![
Space::new().width(Fill),
dialog_button(
crate::tr!("start", "donate"),
Message::DonationPromptDonate,
button::primary,
),
dialog_button(
crate::tr!("donation", "decline"),
Message::CloseModal,
button::secondary,
),
]
.spacing(8)
.align_y(iced::Center),
]
.spacing(18)
.width(sizing.width),
)
.style(dialog_body_style)
.padding([24, 28])
.into()
}
/// One-time default application prompt.
fn default_assoc_dialog_window(
sizing: crate::ui::modal::ModalSizing,
) -> Element<'static, Message> {
+29
View File
@@ -408,6 +408,35 @@ mod tests {
use super::*;
use std::collections::BTreeSet;
#[test]
fn donation_text_is_translated_in_every_locale() {
for language in Language::ALL
.into_iter()
.filter(|language| *language != Language::System)
{
let loader = FluentLanguageLoader::new("opencadstudio", "en-US".parse().unwrap());
load_language(&loader, language).expect("Fluent resources must parse");
let attributes: BTreeSet<String> = loader.with_message_iter(
&language.requested()[0],
|messages| {
messages
.filter(|message| message.id.name == "donation")
.flat_map(|message| {
message.attributes.iter().map(|attr| attr.id.name.to_owned())
})
.collect()
},
);
assert_eq!(
attributes,
BTreeSet::from(["title", "heading", "body", "decline"].map(String::from))
);
for attribute in attributes {
assert!(!loader.get_attr("donation", &attribute).is_empty());
}
}
}
#[test]
fn greek_catalog_loads_and_covers_the_source_catalog() {
let loader = FluentLanguageLoader::new("opencadstudio", "en-US".parse().unwrap());