|
| 1 | +import 'package:equatable/equatable.dart'; |
| 2 | +import 'package:on_time_front/domain/entities/preparation_entity.dart'; |
| 3 | +import 'package:on_time_front/domain/entities/preparation_step_with_time_entity.dart'; |
| 4 | +import 'package:on_time_front/presentation/shared/constants/constants.dart'; |
| 5 | + |
| 6 | +class PreparationWithTimeEntity extends PreparationEntity implements Equatable { |
| 7 | + const PreparationWithTimeEntity({ |
| 8 | + required List<PreparationStepWithTimeEntity> preparationStepList, |
| 9 | + }) : super(preparationStepList: preparationStepList); |
| 10 | + |
| 11 | + factory PreparationWithTimeEntity.fromPreparation( |
| 12 | + PreparationEntity preparation) { |
| 13 | + return PreparationWithTimeEntity( |
| 14 | + preparationStepList: preparation.preparationStepList |
| 15 | + .map( |
| 16 | + (step) => PreparationStepWithTimeEntity( |
| 17 | + id: step.id, |
| 18 | + preparationName: step.preparationName, |
| 19 | + preparationTime: step.preparationTime, |
| 20 | + nextPreparationId: step.nextPreparationId, |
| 21 | + ), |
| 22 | + ) |
| 23 | + .toList(), |
| 24 | + ); |
| 25 | + } |
| 26 | + |
| 27 | + PreparationWithTimeEntity copyWith({ |
| 28 | + List<PreparationStepWithTimeEntity>? preparationStepList, |
| 29 | + }) { |
| 30 | + return PreparationWithTimeEntity( |
| 31 | + preparationStepList: preparationStepList ?? this.preparationStepList, |
| 32 | + ); |
| 33 | + } |
| 34 | + |
| 35 | + @override |
| 36 | + List<PreparationStepWithTimeEntity> get preparationStepList => |
| 37 | + super.preparationStepList.cast<PreparationStepWithTimeEntity>(); |
| 38 | + |
| 39 | + PreparationStepWithTimeEntity? get currentStep { |
| 40 | + for (final step in preparationStepList) { |
| 41 | + if (!step.isDone) { |
| 42 | + return step; |
| 43 | + } |
| 44 | + } |
| 45 | + return null; // All steps are done |
| 46 | + } |
| 47 | + |
| 48 | + /// Returns true if all preparation steps are completed |
| 49 | + bool get isAllStepsDone { |
| 50 | + return currentStep == null; |
| 51 | + } |
| 52 | + |
| 53 | + Duration get elapsedTime => preparationStepList.fold<Duration>( |
| 54 | + Duration.zero, (sum, s) => sum + s.elapsedTime); |
| 55 | + |
| 56 | + /// Returns the progress as a value between 0.0 and 1.0 |
| 57 | + double get progress { |
| 58 | + final totalSeconds = totalDuration.inSeconds; |
| 59 | + final elapsed = elapsedTime.inSeconds; |
| 60 | + return totalSeconds == 0 ? 0.0 : (elapsed / totalSeconds).clamp(0.0, 1.0); |
| 61 | + } |
| 62 | + |
| 63 | + /// Returns the current step index, or -1 if all steps are done |
| 64 | + int get currentStepIndex { |
| 65 | + final current = currentStep; |
| 66 | + if (current == null) return -1; |
| 67 | + return preparationStepList.indexWhere((step) => step.id == current.id); |
| 68 | + } |
| 69 | + |
| 70 | + /// Returns the resolved current step index for display purposes |
| 71 | + int get resolvedCurrentStepIndex { |
| 72 | + final index = currentStepIndex; |
| 73 | + return index == -1 ? preparationStepList.length - 1 : index; |
| 74 | + } |
| 75 | + |
| 76 | + /// Returns the current step's remaining time |
| 77 | + Duration get currentStepRemainingTime { |
| 78 | + final current = currentStep; |
| 79 | + if (current == null) return Duration.zero; |
| 80 | + final remaining = current.preparationTime - current.elapsedTime; |
| 81 | + return remaining.isNegative ? Duration.zero : remaining; |
| 82 | + } |
| 83 | + |
| 84 | + /// Returns the current step's name for display |
| 85 | + String get currentStepName { |
| 86 | + final current = currentStep; |
| 87 | + if (current != null) return current.preparationName; |
| 88 | + return preparationStepList.isNotEmpty |
| 89 | + ? preparationStepList.last.preparationName |
| 90 | + : ''; |
| 91 | + } |
| 92 | + |
| 93 | + /// Returns elapsed times for each step in seconds |
| 94 | + List<int> get stepElapsedTimesInSeconds { |
| 95 | + return preparationStepList |
| 96 | + .map<int>((step) => step.elapsedTime.inSeconds) |
| 97 | + .toList(); |
| 98 | + } |
| 99 | + |
| 100 | + /// Returns the preparation state for each step |
| 101 | + List<PreparationStateEnum> get preparationStepStates { |
| 102 | + final resolvedIndex = resolvedCurrentStepIndex; |
| 103 | + |
| 104 | + return List<PreparationStateEnum>.generate( |
| 105 | + preparationStepList.length, |
| 106 | + (index) { |
| 107 | + if (isAllStepsDone) { |
| 108 | + // All steps are done |
| 109 | + return PreparationStateEnum.done; |
| 110 | + } |
| 111 | + if (index < resolvedIndex) { |
| 112 | + return PreparationStateEnum.done; |
| 113 | + } |
| 114 | + if (index == resolvedIndex && !isAllStepsDone) { |
| 115 | + return PreparationStateEnum.now; |
| 116 | + } |
| 117 | + return PreparationStateEnum.yet; |
| 118 | + }, |
| 119 | + ); |
| 120 | + } |
| 121 | + |
| 122 | + PreparationWithTimeEntity timeElapsed(Duration elapsed) { |
| 123 | + final current = currentStep; |
| 124 | + if (current == null) { |
| 125 | + return this; // All steps are done, no changes needed |
| 126 | + } |
| 127 | + |
| 128 | + Duration remainingElapsed = elapsed; |
| 129 | + List<PreparationStepWithTimeEntity> updatedSteps = |
| 130 | + List.from(preparationStepList); |
| 131 | + |
| 132 | + // Find the current step index |
| 133 | + int currentIndex = updatedSteps.indexWhere((step) => step.id == current.id); |
| 134 | + |
| 135 | + // Apply elapsed time to current and subsequent steps if needed |
| 136 | + while (remainingElapsed > Duration.zero && |
| 137 | + currentIndex < updatedSteps.length) { |
| 138 | + final step = updatedSteps[currentIndex]; |
| 139 | + if (step.isDone) { |
| 140 | + currentIndex++; |
| 141 | + continue; |
| 142 | + } |
| 143 | + |
| 144 | + final stepRemainingTime = step.preparationTime - step.elapsedTime; |
| 145 | + |
| 146 | + if (remainingElapsed >= stepRemainingTime) { |
| 147 | + // Complete this step and move to next |
| 148 | + updatedSteps[currentIndex] = step.copyWith( |
| 149 | + elapsedTime: step.preparationTime, |
| 150 | + isDone: true, |
| 151 | + ); |
| 152 | + remainingElapsed -= stepRemainingTime; |
| 153 | + currentIndex++; |
| 154 | + } else { |
| 155 | + // Partially complete this step |
| 156 | + updatedSteps[currentIndex] = step.copyWith( |
| 157 | + elapsedTime: step.elapsedTime + remainingElapsed, |
| 158 | + isDone: step.elapsedTime + remainingElapsed >= step.preparationTime, |
| 159 | + ); |
| 160 | + remainingElapsed = Duration.zero; |
| 161 | + } |
| 162 | + } |
| 163 | + |
| 164 | + return copyWith(preparationStepList: updatedSteps); |
| 165 | + } |
| 166 | + |
| 167 | + PreparationWithTimeEntity skipCurrentStep() { |
| 168 | + final current = currentStep; |
| 169 | + if (current == null) { |
| 170 | + return this; // All steps are done, no changes needed |
| 171 | + } |
| 172 | + |
| 173 | + final updatedCurrentStep = current.copyWith( |
| 174 | + elapsedTime: current.preparationTime, |
| 175 | + isDone: true, |
| 176 | + ); |
| 177 | + return copyWith( |
| 178 | + preparationStepList: preparationStepList |
| 179 | + .map((step) => |
| 180 | + step.id == updatedCurrentStep.id ? updatedCurrentStep : step) |
| 181 | + .toList(), |
| 182 | + ); |
| 183 | + } |
| 184 | + |
| 185 | + @override |
| 186 | + String toString() { |
| 187 | + return 'PreparationWithTimeEntity(preparationStepList: ${preparationStepList.toString()})'; |
| 188 | + } |
| 189 | + |
| 190 | + @override |
| 191 | + List<Object?> get props => [preparationStepList]; |
| 192 | +} |
0 commit comments