strip unicode dashes, trim restating doc comments, untrack forbidden files

This commit is contained in:
2026-03-13 14:05:59 +02:00
parent 074817def5
commit f6f789baf8
22 changed files with 65 additions and 1438 deletions

View File

@@ -8,7 +8,7 @@ fn main() {
}
// On GNU targets, replace the WebView2Loader import library with the static
// library so the loader is baked into the exe no DLL to ship.
// library so the loader is baked into the exe -- no DLL to ship.
if std::env::var("CARGO_CFG_TARGET_ENV").as_deref() == Ok("gnu") {
swap_webview2_to_static();
}
@@ -44,7 +44,7 @@ fn fix_resource_lib() {
// archive signature). A .res file starts with 0x00000000.
if let Ok(header) = std::fs::read(&lib_file) {
if header.len() >= 4 && header[0..4] == [0, 0, 0, 0] {
// This is a .res file, not COFF re-compile with windres
// This is a .res file, not COFF -- re-compile with windres
let windres = "C:/Users/lashman/mingw-w64/mingw64/bin/windres.exe";
let status = Command::new(windres)
.args([

View File

@@ -3,7 +3,6 @@ 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,
@@ -13,7 +12,6 @@ pub struct CustomActivity {
pub enabled: bool,
}
/// A single time range (e.g., 09:00 to 17:00)
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TimeRange {
pub start: String, // Format: "HH:MM"
@@ -29,7 +27,6 @@ impl Default for TimeRange {
}
}
/// Schedule for a single day
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DaySchedule {
pub enabled: bool,
@@ -46,7 +43,6 @@ impl Default for DaySchedule {
}
impl DaySchedule {
/// Create a default schedule for weekend days (disabled by default)
fn weekend_default() -> Self {
Self {
enabled: false,
@@ -304,14 +300,13 @@ impl Default for Config {
}
impl Config {
/// Get the path to the config file (portable: next to the exe)
// Portable: next to the exe
fn config_path() -> Result<PathBuf> {
let exe_path = std::env::current_exe().context("Failed to determine exe path")?;
let exe_dir = exe_path.parent().context("Failed to determine exe directory")?;
Ok(exe_dir.join("config.json"))
}
/// Load configuration from file, or return default if it doesn't exist
pub fn load_or_default() -> Self {
match Self::load() {
Ok(config) => config,
@@ -327,7 +322,6 @@ impl Config {
}
}
/// Load configuration from file
pub fn load() -> Result<Self> {
let config_path = Self::config_path()?;
@@ -345,7 +339,6 @@ impl Config {
Ok(config.validate())
}
/// Save configuration to file
pub fn save(&self) -> Result<()> {
let config_path = Self::config_path()?;
@@ -357,7 +350,6 @@ impl Config {
Ok(())
}
/// Validate and sanitize configuration values
pub fn validate(mut self) -> Self {
// Break duration: 1-60 minutes
self.break_duration = self.break_duration.clamp(1, 60);
@@ -511,7 +503,6 @@ impl Config {
self
}
/// Check if a time string is in valid HH:MM format
fn is_valid_time_format(time: &str) -> bool {
let parts: Vec<&str> = time.split(':').collect();
if parts.len() != 2 {
@@ -536,29 +527,24 @@ impl Config {
hours * 60 + minutes
}
/// Check if a string is a valid hex color (#RRGGBB)
fn is_valid_hex_color(color: &str) -> bool {
color.len() == 7
&& color.starts_with('#')
&& color[1..].chars().all(|c| c.is_ascii_hexdigit())
}
/// Get break duration in seconds
pub fn break_duration_seconds(&self) -> u64 {
self.break_duration as u64 * 60
}
/// Get break frequency in seconds
pub fn break_frequency_seconds(&self) -> u64 {
self.break_frequency as u64 * 60
}
/// Get snooze duration in seconds
pub fn snooze_duration_seconds(&self) -> u64 {
self.snooze_duration as u64 * 60
}
/// Reset to default values
pub fn reset_to_default(&mut self) {
*self = Self::default();
}

View File

@@ -310,7 +310,6 @@ fn save_window_position(
// ── Dynamic Tray Icon Rendering ────────────────────────────────────────────
/// Parse a "#RRGGBB" hex color string into (r, g, b). Falls back to fallback on invalid input.
fn parse_hex_color(hex: &str, fallback: (u8, u8, u8)) -> (u8, u8, u8) {
if hex.len() == 7 && hex.starts_with('#') {
let r = u8::from_str_radix(&hex[1..3], 16).unwrap_or(fallback.0);
@@ -322,8 +321,6 @@ fn parse_hex_color(hex: &str, fallback: (u8, u8, u8)) -> (u8, u8, u8) {
}
}
/// Render a 32x32 RGBA icon with a progress arc using the given accent/break colors.
/// F10: Optionally renders a green checkmark when daily goal is met.
fn render_tray_icon(
progress: f64,
is_break: bool,
@@ -401,33 +398,31 @@ fn update_tray(
break_color: (u8, u8, u8),
goal_met: bool,
) {
// Update tooltip
let tooltip = match snapshot.state {
timer::TimerState::Running => {
if snapshot.deferred_break_pending {
"Core Cooldown Break deferred (fullscreen)".to_string()
"Core Cooldown -- Break deferred (fullscreen)".to_string()
} else {
let m = snapshot.time_remaining / 60;
let s = snapshot.time_remaining % 60;
format!("Core Cooldown {:02}:{:02} until break", m, s)
format!("Core Cooldown -- {:02}:{:02} until break", m, s)
}
}
timer::TimerState::Paused => {
if snapshot.idle_paused {
"Core Cooldown Paused (idle)".to_string()
"Core Cooldown -- Paused (idle)".to_string()
} else {
"Core Cooldown Paused".to_string()
"Core Cooldown -- Paused".to_string()
}
}
timer::TimerState::BreakActive => {
let m = snapshot.break_time_remaining / 60;
let s = snapshot.break_time_remaining % 60;
format!("Core Cooldown Break {:02}:{:02}", m, s)
format!("Core Cooldown -- Break {:02}:{:02}", m, s)
}
};
let _ = tray.set_tooltip(Some(&tooltip));
// Update icon
let (progress, is_break, is_paused) = match snapshot.state {
timer::TimerState::Running => (snapshot.progress, false, false),
timer::TimerState::Paused => (snapshot.progress, false, true),
@@ -474,7 +469,7 @@ pub fn run() {
"break",
tauri::WebviewUrl::App("index.html?break=1".into()),
)
.title("Core Cooldown \u{2014} Break")
.title("Core Cooldown - Break")
.inner_size(900.0, 540.0)
.decorations(false)
.transparent(true)
@@ -554,7 +549,6 @@ pub fn run() {
let break_c = parse_hex_color(&break_hex, (124, 106, 239));
update_tray(&tray, &snapshot, accent, break_c, goal_met);
// Emit tick event with full snapshot
let _ = handle.emit("timer-tick", &snapshot);
// F5: Screen dim window management
@@ -616,7 +610,6 @@ pub fn run() {
break_deferred_notified = false;
}
TickResult::BreakEnded => {
// Restore normal window state and close break window
handle_break_end(&handle);
// F9: Close multi-monitor overlays
close_multi_monitor_overlays(&handle);
@@ -721,7 +714,7 @@ pub fn run() {
.notification()
.builder()
.title("Break deferred")
.body("Fullscreen app detected break will start when you exit.")
.body("Fullscreen app detected -- break will start when you exit.")
.show();
}
let _ = handle.emit("break-deferred", &());
@@ -883,7 +876,6 @@ fn close_break_window(app: &AppHandle) {
}
}
/// Handle break start: either fullscreen on main window, or open a separate modal break window.
fn handle_break_start(app: &AppHandle, fullscreen_mode: bool) {
if fullscreen_mode {
// Fullscreen: show break inside the main window
@@ -899,7 +891,6 @@ fn handle_break_start(app: &AppHandle, fullscreen_mode: bool) {
}
}
/// Handle break end: restore main window state and close break window if open.
fn handle_break_end(app: &AppHandle) {
if let Some(window) = app.get_webview_window("main") {
let _ = window.set_always_on_top(false);

View File

@@ -9,7 +9,7 @@ use std::sync::atomic::{AtomicI32, Ordering};
// ── MSVC Buffer Security Check (/GS) ────────────────────────────────────────
//
// MSVC's /GS flag instruments functions with stack canaries. These two symbols
// implement the canary check. The cookie value is arbitrary real MSVC CRT
// implement the canary check. The cookie value is arbitrary -- real MSVC CRT
// randomises it at startup, but for a statically-linked helper library this
// fixed sentinel is sufficient.
@@ -44,15 +44,15 @@ pub unsafe extern "C" fn _Init_thread_header(guard: *mut i32) {
loop {
let val = guard.read_volatile();
if val == 0 {
// Already initialised tell caller to skip
// Already initialised -- tell caller to skip
return;
}
if val == -1 {
// Not yet initialised try to claim it
// Not yet initialised -- try to claim it
guard.write_volatile(1);
return;
}
// val == 1: another thread is initialising yield and retry
// val == 1: another thread is initialising -- yield and retry
std::thread::yield_now();
}
}
@@ -71,22 +71,22 @@ pub unsafe extern "C" fn _Init_thread_footer(guard: *mut i32) {
// MinGW's libstdc++ exports the same operators but with GCC/Itanium mangling,
// so the linker can't match them. We provide the MSVC-mangled versions here.
/// `std::nothrow` MSVC-mangled `?nothrow@std@@3Unothrow_t@1@B`
/// `std::nothrow` -- MSVC-mangled `?nothrow@std@@3Unothrow_t@1@B`
/// An empty struct constant used as a tag for nothrow `new`.
#[export_name = "?nothrow@std@@3Unothrow_t@1@B"]
pub static MSVC_STD_NOTHROW: u8 = 0;
/// `operator new(size_t, const std::nothrow_t&)` nothrow allocation
/// `operator new(size_t, const std::nothrow_t&)` -- nothrow allocation
/// MSVC-mangled: `??2@YAPEAX_KAEBUnothrow_t@std@@@Z`
#[export_name = "??2@YAPEAX_KAEBUnothrow_t@std@@@Z"]
pub unsafe extern "C" fn msvc_operator_new_nothrow(size: usize, _nothrow: *const u8) -> *mut u8 {
let size = if size == 0 { 1 } else { size };
let layout = std::alloc::Layout::from_size_align_unchecked(size, 8);
let ptr = std::alloc::alloc(layout);
ptr // null on failure nothrow semantics
ptr // null on failure -- nothrow semantics
}
/// `operator delete(void*, size_t)` sized deallocation
/// `operator delete(void*, size_t)` -- sized deallocation
/// MSVC-mangled: `??3@YAXPEAX_K@Z`
#[export_name = "??3@YAXPEAX_K@Z"]
pub unsafe extern "C" fn msvc_operator_delete_sized(ptr: *mut u8, size: usize) {

View File

@@ -3,7 +3,6 @@ use std::collections::HashMap;
use std::fs;
use std::path::PathBuf;
/// A single day's break statistics.
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(rename_all = "camelCase")]
pub struct DayRecord {
@@ -16,7 +15,6 @@ pub struct DayRecord {
pub natural_break_time_secs: u64,
}
/// Persistent stats stored as JSON.
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct StatsData {
pub days: HashMap<String, DayRecord>,
@@ -24,12 +22,10 @@ pub struct StatsData {
pub best_streak: u32,
}
/// Runtime stats manager.
pub struct Stats {
pub data: StatsData,
}
/// Snapshot sent to the frontend.
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct StatsSnapshot {
@@ -47,13 +43,11 @@ pub struct StatsSnapshot {
pub daily_goal_met: bool,
}
/// F10: Result of recording a completed break
pub struct BreakCompletedResult {
pub milestone_reached: Option<u32>,
pub daily_goal_just_met: bool,
}
/// F7: Weekly summary for reports
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct WeekSummary {
@@ -68,7 +62,7 @@ pub struct WeekSummary {
const MILESTONES: &[u32] = &[3, 5, 7, 14, 21, 30, 50, 100, 365];
impl Stats {
/// Portable: stats file lives next to the exe
// Portable: next to the exe
fn stats_path() -> Option<PathBuf> {
let exe_path = std::env::current_exe().ok()?;
let exe_dir = exe_path.parent()?;
@@ -114,7 +108,6 @@ impl Stats {
})
}
/// Record a completed break. Returns milestone/goal info for gamification.
pub fn record_break_completed(&mut self, duration_secs: u64, daily_goal: u32) -> BreakCompletedResult {
let day = self.today_mut();
let was_below_goal = day.breaks_completed < daily_goal;
@@ -182,7 +175,6 @@ impl Stats {
}
}
/// F10: Check if current streak exactly matches a milestone
fn check_milestone(&self) -> Option<u32> {
let streak = self.data.current_streak;
if MILESTONES.contains(&streak) {
@@ -225,7 +217,6 @@ impl Stats {
}
}
/// Get recent N days of history, sorted chronologically.
pub fn recent_days(&self, n: u32) -> Vec<DayRecord> {
let today = chrono::Local::now().date_naive();
let mut records = Vec::new();
@@ -243,7 +234,6 @@ impl Stats {
records
}
/// F7: Get weekly summaries for the past N weeks
pub fn weekly_summary(&self, weeks: u32) -> Vec<WeekSummary> {
let today = chrono::Local::now().date_naive();
let mut summaries = Vec::new();

View File

@@ -26,7 +26,6 @@ pub enum AppView {
Stats,
}
/// Snapshot of the full timer state, sent to the frontend on every tick
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TimerSnapshot {
@@ -74,7 +73,6 @@ pub struct TimerSnapshot {
pub is_long_break: bool,
}
/// Events emitted by the timer to the frontend
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct BreakStartedPayload {
@@ -161,8 +159,6 @@ impl TimerManager {
}
}
/// Check idle state and auto-pause/resume accordingly.
/// Returns IdleCheckResult indicating what happened.
pub fn check_idle(&mut self) -> IdleCheckResult {
if !self.config.idle_detection_enabled {
// If idle detection disabled but we were idle-paused, resume
@@ -218,7 +214,6 @@ impl TimerManager {
}
}
/// F2: Check if the foreground window is fullscreen (presentation mode)
pub fn check_presentation_mode(&mut self) -> bool {
if !self.config.presentation_mode_enabled {
self.presentation_mode_active = false;
@@ -230,7 +225,6 @@ impl TimerManager {
fs
}
/// Called every second. Returns what events should be emitted.
pub fn tick(&mut self) -> TickResult {
// Idle detection and natural break detection
let idle_result = self.check_idle();
@@ -322,7 +316,6 @@ impl TimerManager {
}
}
/// F1: Called every second for microbreak logic. Returns microbreak events.
pub fn tick_microbreak(&mut self) -> MicrobreakTickResult {
if !self.config.microbreak_enabled {
return MicrobreakTickResult::None;
@@ -416,7 +409,6 @@ impl TimerManager {
self.snoozes_used = 0;
}
/// F3: Advance the Pomodoro cycle position after a break completes
fn advance_pomodoro_cycle(&mut self) {
if !self.config.pomodoro_enabled {
return;
@@ -472,14 +464,14 @@ impl TimerManager {
let past_half = total > 0 && elapsed * 2 >= total;
if past_half && self.config.allow_end_early {
// "End break" counts as completed
// "End break" -- counts as completed
self.has_had_break = true;
self.seconds_since_last_break = 0;
self.advance_pomodoro_cycle();
self.reset_timer();
true
} else if !past_half {
// "Cancel break" doesn't count
// "Cancel break" -- doesn't count
// F3: Pomodoro reset-on-skip
if self.config.pomodoro_enabled && self.config.pomodoro_reset_on_skip {
self.pomodoro_cycle_position = 0;
@@ -672,14 +664,12 @@ pub enum TickResult {
BreakDeferred, // F2
}
/// F1: Microbreak tick result
pub enum MicrobreakTickResult {
None,
MicrobreakStarted,
MicrobreakEnded,
}
/// Result of checking idle state
pub enum IdleCheckResult {
None,
JustPaused,
@@ -687,7 +677,6 @@ pub enum IdleCheckResult {
NaturalBreakDetected(u64), // duration in seconds
}
/// Returns the number of seconds since last user input (mouse/keyboard).
#[cfg(windows)]
pub fn get_idle_seconds() -> u64 {
use std::mem;
@@ -712,7 +701,6 @@ pub fn get_idle_seconds() -> u64 {
0
}
/// F2: Check if the foreground window is a fullscreen application
#[cfg(windows)]
pub fn is_foreground_fullscreen() -> bool {
use std::mem;
@@ -756,7 +744,6 @@ pub fn is_foreground_fullscreen() -> bool {
false
}
/// F9: Get all monitor rects for multi-monitor break enforcement
#[cfg(windows)]
pub fn get_all_monitors() -> Vec<MonitorInfo> {
use winapi::shared::windef::{HMONITOR, HDC, LPRECT};