|
| 1 | +# Donation Dialog Implementation |
| 2 | + |
| 3 | +## Summary |
| 4 | +Successfully implemented a donation prompt dialog that appears on first launch and every 30 days thereafter, with an option to permanently dismiss it. |
| 5 | + |
| 6 | +## Changes Made |
| 7 | + |
| 8 | +### Rust Backend |
| 9 | + |
| 10 | +#### 1. `app/src-tauri/src/types.rs` |
| 11 | +- Added `DonationPromptConfig` struct with: |
| 12 | + - `last_shown: Option<String>` - RFC3339 timestamp of last display |
| 13 | + - `permanently_dismissed: bool` - Flag for "Don't show again" |
| 14 | +- Added `donation_prompt: Option<DonationPromptConfig>` field to `AppConfig` (with `#[serde(default)]` for backward compatibility) |
| 15 | + |
| 16 | +#### 2. `app/src-tauri/src/state.rs` |
| 17 | +- Added `donation_prompt: Arc<Mutex<DonationPromptConfig>>` to `AppState` |
| 18 | +- Initialized in `new()` with `DonationPromptConfig::default()` |
| 19 | +- Updated `save_config()` to include donation_prompt in AppConfig |
| 20 | +- Updated `load_config()` to restore donation_prompt from config.json |
| 21 | + |
| 22 | +#### 3. `app/src-tauri/src/commands.rs` |
| 23 | +- Added `use chrono::{DateTime, Duration, Utc};` for date/time handling |
| 24 | +- Implemented `should_show_donation_prompt()`: |
| 25 | + - Returns `false` if `permanently_dismissed == true` |
| 26 | + - Returns `true` if `last_shown == None` (first launch) |
| 27 | + - Returns `true` if 30+ days have passed since `last_shown` |
| 28 | + - Returns `false` otherwise |
| 29 | +- Implemented `dismiss_donation_prompt(permanently: bool)`: |
| 30 | + - Updates `last_shown` to current timestamp |
| 31 | + - Sets `permanently_dismissed = true` if requested |
| 32 | + - Calls `save_config()` to persist changes |
| 33 | + |
| 34 | +#### 4. `app/src-tauri/src/lib.rs` |
| 35 | +- Registered new commands in `generate_handler!`: |
| 36 | + - `should_show_donation_prompt` |
| 37 | + - `dismiss_donation_prompt` |
| 38 | + |
| 39 | +### React Frontend |
| 40 | + |
| 41 | +#### 5. `app/src/components/DonationDialog.tsx` (New File) |
| 42 | +- Material-UI Dialog component matching existing design patterns |
| 43 | +- Title: "Support vmix-utility" with FavoriteOutlined icon |
| 44 | +- Content: |
| 45 | + - Thank you message |
| 46 | + - Explanation that project is free and open source |
| 47 | + - Three support buttons (matching Developer.tsx style): |
| 48 | + - "Star on GitHub" (secondary color) |
| 49 | + - "GitHub Sponsors" (#13C3FF blue) |
| 50 | + - "Subscribe on Twitch" (#9146FF purple) |
| 51 | + - "Don't show this again" checkbox |
| 52 | +- "Close" button in DialogActions |
| 53 | +- Uses same TwitchIcon SVG as Developer.tsx |
| 54 | + |
| 55 | +#### 6. `app/src/App.tsx` |
| 56 | +- Added imports: `DonationDialog`, `invoke` |
| 57 | +- Added state: `donationDialogOpen` |
| 58 | +- Added useEffect to check dialog display conditions: |
| 59 | + - Only runs on main window (`currentPath === '/'`) |
| 60 | + - Waits 2 seconds after startup |
| 61 | + - Calls `invoke('should_show_donation_prompt')` |
| 62 | + - Opens dialog if backend returns true |
| 63 | +- Added `handleDonationDialogClose()`: |
| 64 | + - Closes dialog |
| 65 | + - Calls `invoke('dismiss_donation_prompt', { permanently })` |
| 66 | +- Rendered `<DonationDialog>` inside `<VMixStatusProvider>` |
| 67 | + |
| 68 | +## Design Considerations |
| 69 | + |
| 70 | +### Backward Compatibility |
| 71 | +- Used `#[serde(default)]` and `Option<DonationPromptConfig>` so existing config.json files work without migration |
| 72 | +- Default values ensure safe behavior for missing fields |
| 73 | + |
| 74 | +### Display Timing |
| 75 | +- 2-second delay after startup to avoid conflicts with: |
| 76 | + - Theme loading |
| 77 | + - Update checker (3-second delay) |
| 78 | +- Only shows on main window (not on popup windows like List Manager) |
| 79 | + |
| 80 | +### State Management |
| 81 | +- Backend centralizes all display logic for consistency |
| 82 | +- Frontend only calls backend commands, no date logic duplication |
| 83 | +- Persistent storage via existing config.json mechanism |
| 84 | + |
| 85 | +### User Experience |
| 86 | +- Non-intrusive: only shows on first launch and monthly |
| 87 | +- Easy to dismiss permanently |
| 88 | +- Uses familiar UI patterns from existing Developer page |
| 89 | +- Accessible via same support buttons throughout the app |
| 90 | + |
| 91 | +## Testing Checklist |
| 92 | + |
| 93 | +1. ✅ First launch: Dialog appears 2 seconds after startup |
| 94 | +2. ⏳ Second launch (within 30 days): Dialog does NOT appear |
| 95 | +3. ⏳ Launch after 30+ days: Dialog appears again |
| 96 | +4. ⏳ "Don't show again" + close: Dialog never appears again (even after 30 days) |
| 97 | +5. ⏳ Manual config.json test: Verify timestamps are saved correctly |
| 98 | +6. ⏳ Popup windows (List Manager): Dialog does NOT appear |
| 99 | +7. ⏳ All support buttons work (open correct URLs) |
| 100 | + |
| 101 | +## Build Status |
| 102 | +✅ Compilation successful (both Rust and TypeScript) |
| 103 | +✅ Debug build completed without errors |
| 104 | +✅ Type checking passed |
| 105 | + |
| 106 | +## Files Modified |
| 107 | +- `app/src-tauri/src/types.rs` |
| 108 | +- `app/src-tauri/src/state.rs` |
| 109 | +- `app/src-tauri/src/commands.rs` |
| 110 | +- `app/src-tauri/src/lib.rs` |
| 111 | +- `app/src/App.tsx` |
| 112 | + |
| 113 | +## Files Created |
| 114 | +- `app/src/components/DonationDialog.tsx` |
| 115 | + |
| 116 | +## Dependencies Used |
| 117 | +- `chrono` - Already in Cargo.toml (for date/time calculations) |
| 118 | +- No new frontend dependencies required |
0 commit comments