mirror of
https://github.com/kuhyx/testsAndMisc-archive.git
synced 2026-07-04 13:23:01 +02:00
206 lines
5.3 KiB
Dart
206 lines
5.3 KiB
Dart
/// Defines the timer style (technique) the user can choose.
|
|
enum TimerStyle {
|
|
/// Classic Pomodoro: 25 min work, 5 min short break, 15 min long break.
|
|
pomodoro,
|
|
|
|
/// Ultraradian rhythm: 90 min work, 30 min break.
|
|
ultraradian,
|
|
}
|
|
|
|
/// Extension on [TimerStyle] to provide display labels and default durations.
|
|
extension TimerStyleConfig on TimerStyle {
|
|
/// Human-readable label for the timer style.
|
|
String get label {
|
|
switch (this) {
|
|
case TimerStyle.pomodoro:
|
|
return 'Pomodoro';
|
|
case TimerStyle.ultraradian:
|
|
return 'Ultraradian';
|
|
}
|
|
}
|
|
|
|
/// Default work duration in minutes.
|
|
int get defaultWorkMinutes {
|
|
switch (this) {
|
|
case TimerStyle.pomodoro:
|
|
return 25;
|
|
case TimerStyle.ultraradian:
|
|
return 90;
|
|
}
|
|
}
|
|
|
|
/// Default short break duration in minutes.
|
|
int get defaultShortBreakMinutes {
|
|
switch (this) {
|
|
case TimerStyle.pomodoro:
|
|
return 5;
|
|
case TimerStyle.ultraradian:
|
|
return 30;
|
|
}
|
|
}
|
|
|
|
/// Default long break duration in minutes.
|
|
int get defaultLongBreakMinutes {
|
|
switch (this) {
|
|
case TimerStyle.pomodoro:
|
|
return 15;
|
|
case TimerStyle.ultraradian:
|
|
return 30;
|
|
}
|
|
}
|
|
|
|
/// Default number of work sessions before a long break.
|
|
int get defaultPomodorosPerCycle {
|
|
switch (this) {
|
|
case TimerStyle.pomodoro:
|
|
return 4;
|
|
case TimerStyle.ultraradian:
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Defines the different modes of a Pomodoro session.
|
|
enum PomodoroMode {
|
|
/// A work session (default 25 minutes).
|
|
work,
|
|
|
|
/// A short break between work sessions (default 5 minutes).
|
|
shortBreak,
|
|
|
|
/// A long break after completing a cycle (default 15 minutes).
|
|
longBreak,
|
|
}
|
|
|
|
/// Extension on [PomodoroMode] to provide display labels.
|
|
extension PomodoroModeLabel on PomodoroMode {
|
|
/// Human-readable label for the mode.
|
|
String get label {
|
|
switch (this) {
|
|
case PomodoroMode.work:
|
|
return 'Work';
|
|
case PomodoroMode.shortBreak:
|
|
return 'Short Break';
|
|
case PomodoroMode.longBreak:
|
|
return 'Long Break';
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Immutable snapshot of the Pomodoro timer state.
|
|
class PomodoroState {
|
|
/// Creates a [PomodoroState].
|
|
const PomodoroState({
|
|
required this.mode,
|
|
required this.remainingSeconds,
|
|
required this.totalSeconds,
|
|
required this.isRunning,
|
|
required this.completedPomodoros,
|
|
required this.pomodorosPerCycle,
|
|
});
|
|
|
|
/// Creates the default initial state.
|
|
factory PomodoroState.initial({
|
|
int workMinutes = 25,
|
|
int shortBreakMinutes = 5,
|
|
int longBreakMinutes = 15,
|
|
int pomodorosPerCycle = 4,
|
|
}) {
|
|
final totalSeconds = workMinutes * 60;
|
|
return PomodoroState(
|
|
mode: PomodoroMode.work,
|
|
remainingSeconds: totalSeconds,
|
|
totalSeconds: totalSeconds,
|
|
isRunning: false,
|
|
completedPomodoros: 0,
|
|
pomodorosPerCycle: pomodorosPerCycle,
|
|
);
|
|
}
|
|
|
|
/// The current timer mode.
|
|
final PomodoroMode mode;
|
|
|
|
/// Seconds left on the current timer.
|
|
final int remainingSeconds;
|
|
|
|
/// Total seconds for the current mode.
|
|
final int totalSeconds;
|
|
|
|
/// Whether the timer is currently running.
|
|
final bool isRunning;
|
|
|
|
/// Number of completed work sessions in the current cycle.
|
|
final int completedPomodoros;
|
|
|
|
/// Number of pomodoros before a long break.
|
|
final int pomodorosPerCycle;
|
|
|
|
/// Progress as a value between 0.0 and 1.0.
|
|
double get progress {
|
|
if (totalSeconds == 0) return 1.0;
|
|
return 1.0 - (remainingSeconds / totalSeconds);
|
|
}
|
|
|
|
/// Display label for the current mode, context-aware.
|
|
///
|
|
/// When [pomodorosPerCycle] is 1 (e.g. ultraradian), breaks are simply
|
|
/// labelled "Break" instead of "Short Break" or "Long Break".
|
|
String get modeDisplayLabel {
|
|
if (pomodorosPerCycle <= 1 && mode != PomodoroMode.work) {
|
|
return 'Break';
|
|
}
|
|
return mode.label;
|
|
}
|
|
|
|
/// Formatted time string (MM:SS).
|
|
String get formattedTime {
|
|
final minutes = remainingSeconds ~/ 60;
|
|
final seconds = remainingSeconds % 60;
|
|
return '${minutes.toString().padLeft(2, '0')}:'
|
|
'${seconds.toString().padLeft(2, '0')}';
|
|
}
|
|
|
|
/// Creates a copy with the given fields replaced.
|
|
PomodoroState copyWith({
|
|
PomodoroMode? mode,
|
|
int? remainingSeconds,
|
|
int? totalSeconds,
|
|
bool? isRunning,
|
|
int? completedPomodoros,
|
|
int? pomodorosPerCycle,
|
|
}) {
|
|
return PomodoroState(
|
|
mode: mode ?? this.mode,
|
|
remainingSeconds: remainingSeconds ?? this.remainingSeconds,
|
|
totalSeconds: totalSeconds ?? this.totalSeconds,
|
|
isRunning: isRunning ?? this.isRunning,
|
|
completedPomodoros: completedPomodoros ?? this.completedPomodoros,
|
|
pomodorosPerCycle: pomodorosPerCycle ?? this.pomodorosPerCycle,
|
|
);
|
|
}
|
|
|
|
@override
|
|
bool operator ==(Object other) {
|
|
if (identical(this, other)) return true;
|
|
return other is PomodoroState &&
|
|
other.mode == mode &&
|
|
other.remainingSeconds == remainingSeconds &&
|
|
other.totalSeconds == totalSeconds &&
|
|
other.isRunning == isRunning &&
|
|
other.completedPomodoros == completedPomodoros &&
|
|
other.pomodorosPerCycle == pomodorosPerCycle;
|
|
}
|
|
|
|
@override
|
|
int get hashCode {
|
|
return Object.hash(
|
|
mode,
|
|
remainingSeconds,
|
|
totalSeconds,
|
|
isRunning,
|
|
completedPomodoros,
|
|
pomodorosPerCycle,
|
|
);
|
|
}
|
|
}
|