using Contime.data; using Contime.model; using Contime.view; namespace Contime.controller { public class TimeTrackerController { private readonly TimeTrackerModel _model; private readonly MainForm _view; private readonly System.Windows.Forms.Timer _timer; private const int IDLE_NOTIFICATION_MINUTES = 15; private const int ACTIVE_TASK_NOTIFICATION_MINUTES = 60; private bool _idleNotificationSent = false; private bool _activeTaskNotificationSent = false; public TimeTrackerController(TimeTrackerModel model, MainForm view) { _model = model; _view = view; // Subscribe to model and view events _model.StateChanged += OnModelStateChanged; _model.MajorStateChanged += OnModelMajorStateChanged; _view.WorkdayStartStopClicked += () => _model.StartStopWorkday(); _view.TaskStartStopClicked += () => _model.StartStopTask(); _view.GoOutOfContextClicked += () => _model.SwitchContext(); _view.ToggleTaskStatusClicked += () => _model.ToggleSelectedTaskStatus(); _view.AddTaskClicked += () => _model.AddTask(_view.NewTaskName); _view.TaskSelected += (taskId) => _model.SelectTask(taskId); _view.SaveContextClicked += () => _model.OutOfContextReason = _view.ContextText; _view.ExportClicked += OnExportClicked; // Setup the main timer _timer = new System.Windows.Forms.Timer { Interval = 1000 }; _timer.Tick += OnTimerTick; // Initial UI update _view.UpdateView(_model); } private void OnTimerTick(object sender, EventArgs e) { if (_model.CurrentState == TimeTrackerModel.AppState.Idle) { _timer.Stop(); return; } _view.UpdateTimersAndState(_model); CheckNotifications(); } private void OnModelStateChanged() { if (_model.CurrentState != TimeTrackerModel.AppState.Idle && !_timer.Enabled) { _timer.Start(); } _view.UpdateTimersAndState(_model); // Reset notification flags on state change _idleNotificationSent = false; _activeTaskNotificationSent = false; } private void OnModelMajorStateChanged() { // A major state change might require starting the timer (e.g., starting the workday) if (_model.CurrentState != TimeTrackerModel.AppState.Idle && !_timer.Enabled) { _timer.Start(); } // This event is for when the task list needs a full refresh _view.UpdateView(_model); } private void CheckNotifications() { // Notification for being idle (workday active, no task) if (_model.CurrentState == TimeTrackerModel.AppState.WorkdayActive && _model.IdleTime.TotalMinutes >= IDLE_NOTIFICATION_MINUTES && !_idleNotificationSent) { _view.ShowNotification("Task Reminder", "You've been idle for over 15 minutes. Remember to select a task."); _idleNotificationSent = true; } // Notification for a long-running task if (_model.CurrentState == TimeTrackerModel.AppState.TaskActive && _model.ActiveTaskTime.TotalMinutes >= ACTIVE_TASK_NOTIFICATION_MINUTES && !_activeTaskNotificationSent) { _view.ShowNotification("Task Check-in", $"The current task has been running for over an hour. Still on it?"); _activeTaskNotificationSent = true; } } private void OnExportClicked() { using (var sfd = new SaveFileDialog()) { sfd.Filter = "Excel Workbook|*.xlsx"; sfd.ValidateNames = true; sfd.FileName = $"Contime_Report_{DateTime.Now:yyyy-MM-dd}.xlsx"; if (sfd.ShowDialog() == DialogResult.OK) { try { var exporter = new ExcelExporter(_model.DataAccess); exporter.Export(sfd.FileName); _view.ShowNotification("Export Successful", $"Report saved to {sfd.FileName}"); } catch (Exception ex) { MessageBox.Show($"An error occurred during export: {ex.Message}", "Export Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } } } } }