Add pomodoro, microbreaks, breathing guide, screen dimming, presentation mode, goals, multi-monitor, and activity manager

This commit is contained in:
2026-02-07 15:11:44 +02:00
parent 3ca3857141
commit be41f61740
28 changed files with 3792 additions and 448 deletions

View File

@@ -3,6 +3,16 @@ use serde::{Deserialize, Serialize};
use std::fs;
use std::path::PathBuf;
/// A custom break activity defined by the user.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CustomActivity {
pub id: String,
pub category: String,
pub text: String,
pub is_favorite: bool,
pub enabled: bool,
}
/// A single time range (e.g., 09:00 to 17:00)
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TimeRange {
@@ -107,6 +117,54 @@ pub struct Config {
pub mini_click_through: bool, // Mini mode is click-through until hovered
pub mini_hover_threshold: f32, // Seconds to hover before enabling drag (1.0-10.0)
// F8: Auto-start on Windows login
pub auto_start_on_login: bool,
// F6: Custom break activities
pub custom_activities: Vec<CustomActivity>,
pub disabled_builtin_activities: Vec<String>,
pub favorite_builtin_activities: Vec<String>,
pub favorite_weight: u32, // Multiplier for favorites in random pool (2-10)
// F4: Guided breathing animation
pub breathing_guide_enabled: bool,
pub breathing_pattern: String, // "box", "relaxing", "energizing", "calm", "deep"
// F10: Break streaks & gamification
pub daily_goal_enabled: bool,
pub daily_goal_breaks: u32, // 1-30
pub milestone_celebrations: bool,
pub streak_notifications: bool,
// F1: Microbreaks & 20-20-20
pub microbreak_enabled: bool,
pub microbreak_frequency: u32, // 5-60 min
pub microbreak_duration: u32, // 10-60 sec
pub microbreak_sound_enabled: bool,
pub microbreak_show_activity: bool,
pub microbreak_pause_during_break: bool,
// F3: Pomodoro Mode
pub pomodoro_enabled: bool,
pub pomodoro_short_breaks: u32, // 1-10 (short breaks before long)
pub pomodoro_long_break_duration: u32, // 5-60 min
pub pomodoro_long_break_title: String, // max 100 chars
pub pomodoro_long_break_message: String, // max 500 chars
pub pomodoro_reset_on_skip: bool,
// F5: Screen dimming pre-break nudge
pub screen_dim_enabled: bool,
pub screen_dim_seconds: u32, // 3-60 sec before break
pub screen_dim_max_opacity: f32, // 0.1-0.7
// F2: Presentation mode / fullscreen detection
pub presentation_mode_enabled: bool,
pub presentation_mode_defer_microbreaks: bool,
pub presentation_mode_notification: bool,
// F9: Multi-monitor break enforcement
pub multi_monitor_break: bool,
// Window positions (persisted between launches)
pub main_window_x: Option<i32>,
pub main_window_y: Option<i32>,
@@ -186,6 +244,54 @@ impl Default for Config {
mini_click_through: true,
mini_hover_threshold: 3.0,
// F8: Auto-start
auto_start_on_login: false,
// F6: Custom activities
custom_activities: Vec::new(),
disabled_builtin_activities: Vec::new(),
favorite_builtin_activities: Vec::new(),
favorite_weight: 3,
// F4: Breathing guide
breathing_guide_enabled: true,
breathing_pattern: "box".to_string(),
// F10: Gamification
daily_goal_enabled: true,
daily_goal_breaks: 8,
milestone_celebrations: true,
streak_notifications: true,
// F1: Microbreaks
microbreak_enabled: false,
microbreak_frequency: 20,
microbreak_duration: 20,
microbreak_sound_enabled: true,
microbreak_show_activity: true,
microbreak_pause_during_break: true,
// F3: Pomodoro
pomodoro_enabled: false,
pomodoro_short_breaks: 3,
pomodoro_long_break_duration: 15,
pomodoro_long_break_title: "Long break".to_string(),
pomodoro_long_break_message: "Great work! Take a longer rest.".to_string(),
pomodoro_reset_on_skip: false,
// F5: Screen dimming
screen_dim_enabled: false,
screen_dim_seconds: 10,
screen_dim_max_opacity: 0.3,
// F2: Presentation mode
presentation_mode_enabled: true,
presentation_mode_defer_microbreaks: true,
presentation_mode_notification: true,
// F9: Multi-monitor
multi_monitor_break: true,
// Window positions
main_window_x: None,
main_window_y: None,
@@ -349,6 +455,44 @@ impl Config {
// UI zoom: 50-200%
self.ui_zoom = self.ui_zoom.clamp(50, 200);
// F6: Custom activities
if self.custom_activities.len() > 100 {
self.custom_activities.truncate(100);
}
for act in &mut self.custom_activities {
if act.text.len() > 500 {
act.text.truncate(500);
}
}
self.favorite_weight = self.favorite_weight.clamp(2, 10);
// F4: Breathing pattern
let valid_patterns = vec!["box", "relaxing", "energizing", "calm", "deep"];
if !valid_patterns.contains(&self.breathing_pattern.as_str()) {
self.breathing_pattern = "box".to_string();
}
// F10: Daily goal
self.daily_goal_breaks = self.daily_goal_breaks.clamp(1, 30);
// F1: Microbreaks
self.microbreak_frequency = self.microbreak_frequency.clamp(5, 60);
self.microbreak_duration = self.microbreak_duration.clamp(10, 60);
// F3: Pomodoro
self.pomodoro_short_breaks = self.pomodoro_short_breaks.clamp(1, 10);
self.pomodoro_long_break_duration = self.pomodoro_long_break_duration.clamp(5, 60);
if self.pomodoro_long_break_title.len() > 100 {
self.pomodoro_long_break_title.truncate(100);
}
if self.pomodoro_long_break_message.len() > 500 {
self.pomodoro_long_break_message.truncate(500);
}
// F5: Screen dimming
self.screen_dim_seconds = self.screen_dim_seconds.clamp(3, 60);
self.screen_dim_max_opacity = self.screen_dim_max_opacity.clamp(0.1, 0.7);
// Validate color hex strings
if !Self::is_valid_hex_color(&self.accent_color) {
self.accent_color = "#ff4d00".to_string();