234 lines
6.3 KiB
TypeScript
234 lines
6.3 KiB
TypeScript
import { writable, get } from "svelte/store";
|
|
import { invoke } from "@tauri-apps/api/core";
|
|
|
|
export interface TimeRange {
|
|
start: string; // Format: "HH:MM"
|
|
end: string; // Format: "HH:MM"
|
|
}
|
|
|
|
export interface DaySchedule {
|
|
enabled: boolean;
|
|
ranges: TimeRange[];
|
|
}
|
|
|
|
export interface CustomActivity {
|
|
id: string;
|
|
category: string;
|
|
text: string;
|
|
is_favorite: boolean;
|
|
enabled: boolean;
|
|
}
|
|
|
|
export interface Config {
|
|
break_duration: number;
|
|
break_frequency: number;
|
|
auto_start: boolean;
|
|
break_title: string;
|
|
break_message: string;
|
|
fullscreen_mode: boolean;
|
|
strict_mode: boolean;
|
|
allow_end_early: boolean;
|
|
immediately_start_breaks: boolean;
|
|
working_hours_enabled: boolean;
|
|
working_hours_schedule: DaySchedule[];
|
|
dark_mode: boolean;
|
|
color_scheme: string;
|
|
backdrop_opacity: number;
|
|
notification_enabled: boolean;
|
|
notification_before_break: number;
|
|
snooze_duration: number;
|
|
snooze_limit: number;
|
|
skip_cooldown: number;
|
|
sound_enabled: boolean;
|
|
sound_volume: number;
|
|
sound_preset: string;
|
|
idle_detection_enabled: boolean;
|
|
idle_timeout: number;
|
|
smart_breaks_enabled: boolean;
|
|
smart_break_threshold: number;
|
|
smart_break_count_stats: boolean;
|
|
show_break_activities: boolean;
|
|
ui_zoom: number;
|
|
accent_color: string;
|
|
break_color: string;
|
|
countdown_font: string;
|
|
background_blobs_enabled: boolean;
|
|
mini_click_through: boolean;
|
|
mini_hover_threshold: number;
|
|
// F8: Auto-start on login
|
|
auto_start_on_login: boolean;
|
|
// F6: Custom activities
|
|
custom_activities: CustomActivity[];
|
|
disabled_builtin_activities: string[];
|
|
favorite_builtin_activities: string[];
|
|
favorite_weight: number;
|
|
// F4: Breathing guide
|
|
breathing_guide_enabled: boolean;
|
|
breathing_pattern: string;
|
|
// F10: Gamification
|
|
daily_goal_enabled: boolean;
|
|
daily_goal_breaks: number;
|
|
milestone_celebrations: boolean;
|
|
streak_notifications: boolean;
|
|
// F1: Microbreaks
|
|
microbreak_enabled: boolean;
|
|
microbreak_frequency: number;
|
|
microbreak_duration: number;
|
|
microbreak_sound_enabled: boolean;
|
|
microbreak_show_activity: boolean;
|
|
microbreak_pause_during_break: boolean;
|
|
// F3: Pomodoro
|
|
pomodoro_enabled: boolean;
|
|
pomodoro_short_breaks: number;
|
|
pomodoro_long_break_duration: number;
|
|
pomodoro_long_break_title: string;
|
|
pomodoro_long_break_message: string;
|
|
pomodoro_reset_on_skip: boolean;
|
|
// F5: Screen dimming
|
|
screen_dim_enabled: boolean;
|
|
screen_dim_seconds: number;
|
|
screen_dim_max_opacity: number;
|
|
// F2: Presentation mode
|
|
presentation_mode_enabled: boolean;
|
|
presentation_mode_defer_microbreaks: boolean;
|
|
presentation_mode_notification: boolean;
|
|
// F9: Multi-monitor
|
|
multi_monitor_break: boolean;
|
|
}
|
|
|
|
const defaultConfig: Config = {
|
|
break_duration: 5,
|
|
break_frequency: 25,
|
|
auto_start: true,
|
|
break_title: "Rest your eyes",
|
|
break_message: "Look away from the screen. Stretch and relax.",
|
|
fullscreen_mode: true,
|
|
strict_mode: false,
|
|
allow_end_early: true,
|
|
immediately_start_breaks: false,
|
|
working_hours_enabled: false,
|
|
working_hours_schedule: [
|
|
{ enabled: true, ranges: [{ start: "09:00", end: "18:00" }] },
|
|
{ enabled: true, ranges: [{ start: "09:00", end: "18:00" }] },
|
|
{ enabled: true, ranges: [{ start: "09:00", end: "18:00" }] },
|
|
{ enabled: true, ranges: [{ start: "09:00", end: "18:00" }] },
|
|
{ enabled: true, ranges: [{ start: "09:00", end: "18:00" }] },
|
|
{ enabled: false, ranges: [{ start: "09:00", end: "18:00" }] },
|
|
{ enabled: false, ranges: [{ start: "09:00", end: "18:00" }] },
|
|
],
|
|
dark_mode: true,
|
|
color_scheme: "Ocean",
|
|
backdrop_opacity: 0.92,
|
|
notification_enabled: true,
|
|
notification_before_break: 30,
|
|
snooze_duration: 5,
|
|
snooze_limit: 3,
|
|
skip_cooldown: 60,
|
|
sound_enabled: true,
|
|
sound_volume: 70,
|
|
sound_preset: "bell",
|
|
idle_detection_enabled: true,
|
|
idle_timeout: 120,
|
|
smart_breaks_enabled: true,
|
|
smart_break_threshold: 300,
|
|
smart_break_count_stats: false,
|
|
show_break_activities: true,
|
|
ui_zoom: 100,
|
|
accent_color: "#ff4d00",
|
|
break_color: "#7c6aef",
|
|
countdown_font: "",
|
|
background_blobs_enabled: true,
|
|
mini_click_through: true,
|
|
mini_hover_threshold: 3.0,
|
|
// F8
|
|
auto_start_on_login: false,
|
|
// F6
|
|
custom_activities: [],
|
|
disabled_builtin_activities: [],
|
|
favorite_builtin_activities: [],
|
|
favorite_weight: 3,
|
|
// F4
|
|
breathing_guide_enabled: true,
|
|
breathing_pattern: "box",
|
|
// F10
|
|
daily_goal_enabled: true,
|
|
daily_goal_breaks: 8,
|
|
milestone_celebrations: true,
|
|
streak_notifications: true,
|
|
// F1
|
|
microbreak_enabled: false,
|
|
microbreak_frequency: 20,
|
|
microbreak_duration: 20,
|
|
microbreak_sound_enabled: true,
|
|
microbreak_show_activity: true,
|
|
microbreak_pause_during_break: true,
|
|
// F3
|
|
pomodoro_enabled: false,
|
|
pomodoro_short_breaks: 3,
|
|
pomodoro_long_break_duration: 15,
|
|
pomodoro_long_break_title: "Long break",
|
|
pomodoro_long_break_message: "Great work! Take a longer rest.",
|
|
pomodoro_reset_on_skip: false,
|
|
// F5
|
|
screen_dim_enabled: false,
|
|
screen_dim_seconds: 10,
|
|
screen_dim_max_opacity: 0.3,
|
|
// F2
|
|
presentation_mode_enabled: true,
|
|
presentation_mode_defer_microbreaks: true,
|
|
presentation_mode_notification: true,
|
|
// F9
|
|
multi_monitor_break: true,
|
|
};
|
|
|
|
export const config = writable<Config>(defaultConfig);
|
|
|
|
export async function loadConfig() {
|
|
try {
|
|
const cfg = await invoke<Config>("get_config");
|
|
config.set(cfg);
|
|
} catch (e) {
|
|
console.error("Failed to load config:", e);
|
|
}
|
|
}
|
|
|
|
export async function saveConfig(): Promise<boolean> {
|
|
try {
|
|
const cfg = get(config);
|
|
await invoke("save_config", { config: cfg });
|
|
return true;
|
|
} catch (e) {
|
|
console.error("Failed to save config:", e);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
export async function notifyConfigChanged() {
|
|
try {
|
|
const cfg = get(config);
|
|
await invoke("update_pending_config", { config: cfg });
|
|
} catch (e) {
|
|
console.error("Failed to update pending config:", e);
|
|
}
|
|
}
|
|
|
|
export async function resetConfig() {
|
|
try {
|
|
const cfg = await invoke<Config>("reset_config");
|
|
config.set(cfg);
|
|
} catch (e) {
|
|
console.error("Failed to reset config:", e);
|
|
}
|
|
}
|
|
|
|
// Debounced auto-save: updates backend immediately, persists to disk after 400ms idle
|
|
let saveTimer: ReturnType<typeof setTimeout> | null = null;
|
|
|
|
export function autoSave() {
|
|
notifyConfigChanged();
|
|
if (saveTimer) clearTimeout(saveTimer);
|
|
saveTimer = setTimeout(() => {
|
|
saveConfig();
|
|
}, 400);
|
|
}
|