144 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			C#
		
	
	
	
			
		
		
	
	
			144 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			C#
		
	
	
	
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();
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 |