forked from 1b-agent/opencadstudio-upstream
Show donation request once per app version
This commit is contained in:
1 parent
1b0a42a35c
commit
2c83ae2736
28 files changed
+332
-24
No files matched your search
@@ -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 = اختصارات لوحة المفاتيح
|
||||
|
||||
@@ -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 = Клавишни комбинации
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 = Συντομεύσεις πληκτρολογίου
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 = कीबोर्ड शॉर्टकट
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 = キーボードショートカット
|
||||
|
||||
@@ -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 = 키보드 단축키
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 = Настройки клавиатуры
|
||||
|
||||
@@ -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ı
|
||||
|
||||
@@ -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 = 键盘快捷键
|
||||
|
||||
@@ -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
@@ -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
@@ -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,
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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());
|
||||
|
||||
Reference in new issue
Block a user