From b446786d7d825494a033607663a2aaeb894ff34e Mon Sep 17 00:00:00 2001 From: Hakan Seven Date: Wed, 8 Jul 2026 00:32:12 +0300 Subject: [PATCH] feat(supporters): merge hand-maintained supporters, rank by amount Add a MANUAL_SUPPORTERS list in patreon.rs for donations that arrive outside Patreon; both the native and web boot paths merge it with the fetched patrons and sort the combined list by amount (highest first, then alphabetically). This also sorts the web supporters list, which previously arrived unordered, and keeps hand-maintained supporters visible when the Patreon fetch returns nothing (offline / no token). Co-Authored-By: Claude Opus 4.8 --- src/app/update/mod.rs | 13 +++++++++---- src/patreon.rs | 28 ++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/app/update/mod.rs b/src/app/update/mod.rs index 6bab75c96..34ebe8e8d 100644 --- a/src/app/update/mod.rs +++ b/src/app/update/mod.rs @@ -2730,12 +2730,17 @@ impl OpenCADStudio { Task::none() } Message::PatronsFetched(Ok(names)) => { - self.patrons = names; + // Merge the hand-maintained supporters and rank everyone by + // amount (also sorts the web list, which arrives unsorted). + self.patrons = crate::patreon::merge_manual(names); + Task::none() + } + // No token / offline: still show any hand-maintained supporters + // (Start page shows a "Support on Patreon" prompt when empty). + Message::PatronsFetched(Err(_)) => { + self.patrons = crate::patreon::merge_manual(Vec::new()); Task::none() } - // No token / offline: leave the list empty (Start page shows a - // "Support on Patreon" prompt instead). - Message::PatronsFetched(Err(_)) => Task::none(), Message::PluginReleasesFetched(repo, Ok(tags)) => { if let Some(first) = tags.first() { self.repo_selected_tag diff --git a/src/patreon.rs b/src/patreon.rs index d2d425d6e..01eba0a61 100644 --- a/src/patreon.rs +++ b/src/patreon.rs @@ -7,6 +7,34 @@ //! can still be extracted from a shipped binary, so it should be a //! campaign-scoped token with the minimum needed access. +/// Supporters who donated outside Patreon (direct transfer, crypto, one-off +/// gifts, …), maintained by hand here. They are merged with the fetched patrons +/// and ranked together by amount, so the combined Start-page list is ordered by +/// pledge regardless of where the donation came from. +/// +/// To add a supporter, add a `("Display name", cents)` line below. The amount is +/// in **cents**: a $25 donation is `2500`, €10 is `1000`. +const MANUAL_SUPPORTERS: &[(&str, i64)] = &[ + ("Stefano", 6000), // $60 +]; + +/// Append the hand-maintained [`MANUAL_SUPPORTERS`] to `patrons` and sort the +/// combined list by amount (highest first, then alphabetically). Both the +/// native and web boot paths funnel their fetched list through here, so the +/// manual entries — and the ranking — are identical on every platform, and the +/// list is still sorted (and still shows the manual entries) even when the +/// fetch returns nothing because the app is offline or has no Patreon token. +pub fn merge_manual(mut patrons: Vec<(String, i64)>) -> Vec<(String, i64)> { + for &(name, cents) in MANUAL_SUPPORTERS { + let name = name.trim(); + if !name.is_empty() { + patrons.push((name.to_string(), cents)); + } + } + patrons.sort_by(|a, b| b.1.cmp(&a.1).then_with(|| a.0.cmp(&b.0))); + patrons +} + #[cfg(not(target_arch = "wasm32"))] const UA: &str = concat!("OpenCADStudio/", env!("CARGO_PKG_VERSION"));