ConTime/model/TimeTrackerModel.cs

144 lines
5.5 KiB
C#
Raw Permalink Normal View History

2025-10-12 21:47:06 +00:00
using Contime.data;
using System.Diagnostics;
namespace Contime.model {
public class TimeTrackerModel {
// --- Public State & Data ---
public enum AppState { Idle, WorkdayActive, TaskActive, OutOfContext }
public AppState CurrentState { get; private set; } = AppState.Idle;
public List<TaskItem> Tasks { get; private set; } = new List<TaskItem>();
public TaskItem SelectedTask { get; private set; }
public string OutOfContextReason { get; set; } = "";
public DataAccess DataAccess => _dataAccess;
// --- Public Read-only Timer Properties ---
public TimeSpan WorkdayTime => _workdayStopwatch.Elapsed;
public TimeSpan ActiveTaskTime => _activeTaskStopwatch.Elapsed;
public TimeSpan IdleTime => _idleStopwatch.Elapsed;
public TimeSpan SelectedTaskTotalTime => SelectedTask?.ElapsedTime ?? TimeSpan.Zero;
public TimeSpan DayTotal { get; private set; } = TimeSpan.Zero;
public TimeSpan WeekTotal { get; private set; } = TimeSpan.Zero;
// --- Events ---
public event Action StateChanged; // For high-frequency updates (timers)
public event Action MajorStateChanged; // For low-frequency updates (task list)
// --- Private Fields ---
private readonly DataAccess _dataAccess;
private readonly Stopwatch _workdayStopwatch = new Stopwatch();
private readonly Stopwatch _activeTaskStopwatch = new Stopwatch();
private readonly Stopwatch _idleStopwatch = new Stopwatch();
private long _currentWorkdayId;
private long _currentTaskTimeId;
public TimeTrackerModel(DataAccess dataAccess) {
_dataAccess = dataAccess;
ReloadAllData(); // Initial load
}
private void ReloadAllData() {
long? selectedTaskId = SelectedTask?.Id;
Tasks = _dataAccess.GetAllTasks();
DayTotal = _dataAccess.GetTotalTimeForDate(DateTime.Today);
WeekTotal = _dataAccess.GetTotalTimeForCurrentWeek();
if (selectedTaskId.HasValue) {
SelectedTask = Tasks.FirstOrDefault(t => t.Id == selectedTaskId.Value);
}
MajorStateChanged?.Invoke();
}
// --- Public Methods (State Changers) ---
public void StartStopWorkday() {
if (CurrentState == AppState.Idle) {
_currentWorkdayId = _dataAccess.GetOrCreateWorkday(DateTime.Today);
CurrentState = AppState.WorkdayActive;
_workdayStopwatch.Restart();
_idleStopwatch.Restart();
}
else {
if (CurrentState == AppState.TaskActive) StopTask();
CurrentState = AppState.Idle;
_workdayStopwatch.Stop();
_idleStopwatch.Stop();
SelectedTask = null;
}
ReloadAllData();
}
public void SelectTask(long taskId) {
if (SelectedTask?.Id == taskId) return; // Prevent re-selection loop
SelectedTask = taskId == -1 ? null : Tasks.FirstOrDefault(t => t.Id == taskId);
// A selection change is a major state change that affects buttons
MajorStateChanged?.Invoke();
}
public void StartStopTask() {
if (CurrentState == AppState.TaskActive) // Stopping
{
StopTask();
}
else if (CurrentState == AppState.WorkdayActive && SelectedTask != null && SelectedTask.Status == "open") // Starting
{
_currentTaskTimeId = _dataAccess.StartTaskTime(SelectedTask.Id, _currentWorkdayId);
CurrentState = AppState.TaskActive;
_activeTaskStopwatch.Restart();
_idleStopwatch.Stop();
_idleStopwatch.Reset();
}
ReloadAllData();
}
public void SwitchContext() {
if (CurrentState == AppState.OutOfContext) // Returning
{
CurrentState = _currentTaskTimeId > 0 ? AppState.TaskActive : AppState.WorkdayActive;
_workdayStopwatch.Start();
if (CurrentState == AppState.TaskActive) _activeTaskStopwatch.Start();
else _idleStopwatch.Start();
}
else if (CurrentState != AppState.Idle) // Going
{
_workdayStopwatch.Stop();
if (CurrentState == AppState.TaskActive) _activeTaskStopwatch.Stop();
if (CurrentState == AppState.WorkdayActive) _idleStopwatch.Stop();
CurrentState = AppState.OutOfContext;
}
StateChanged?.Invoke();
}
public void AddTask(string name) {
if (string.IsNullOrWhiteSpace(name)) return;
_dataAccess.AddTask(name);
ReloadAllData();
}
public void ToggleSelectedTaskStatus() {
if (SelectedTask == null || CurrentState == AppState.TaskActive) return;
string newStatus = SelectedTask.Status == "open" ? "closed" : "open";
_dataAccess.UpdateTaskStatus(SelectedTask.Id, newStatus, newStatus == "closed");
ReloadAllData();
}
private void StopTask() {
if (!_activeTaskStopwatch.IsRunning) return;
_dataAccess.EndTaskTime(_currentTaskTimeId);
_currentTaskTimeId = 0;
CurrentState = AppState.WorkdayActive;
_activeTaskStopwatch.Stop();
_activeTaskStopwatch.Reset();
_idleStopwatch.Restart();
}
}
}