mirror of
https://github.com/dralkh/spaceforge.git
synced 2026-07-22 16:40:30 +00:00
feat(pomodoro): enhance timer with estimation overrides and detailed cycle tracking
- Add user override interface for custom time estimation (H/M inputs with add/replace toggle) - Implement override-only calculation when no notes are available - Fix cycle tracking to update/reset on each calculation - Enhance cycle progress display format: "Cycles X/X - Sessions X/X - XH/XM" - Separate Pomodoro visibility from review buttons for persistent display - Add comprehensive estimation logic supporting both note-based and override-only scenarios - Improve UI styling with focus states, better visual hierarchy, and responsive layout
This commit is contained in:
parent
52efa857af
commit
265b866d44
10 changed files with 894 additions and 104 deletions
337
main.js
337
main.js
|
|
@ -4356,6 +4356,12 @@ var PomodoroUIManager = class {
|
|||
this.pomodoroQuickLongInput = null;
|
||||
this.pomodoroQuickSessionsInput = null;
|
||||
this.pomodoroCalculationResultEl = null;
|
||||
// New estimation and cycle tracking elements (moved to calculation panel)
|
||||
this.pomodoroCycleProgressEl = null;
|
||||
// User override input elements
|
||||
this.pomodoroUserOverrideHoursInput = null;
|
||||
this.pomodoroUserOverrideMinutesInput = null;
|
||||
this.pomodoroUserAddToEstimationCheckbox = null;
|
||||
// private isPomodoroSectionOpen: boolean = false; // No longer needed, section is always "open"
|
||||
this.areButtonsVisible = true;
|
||||
// For Play/Pause/Skip buttons
|
||||
|
|
@ -4432,7 +4438,7 @@ var PomodoroUIManager = class {
|
|||
* @param container The parent element to render into (this.pomodoroRootEl).
|
||||
*/
|
||||
renderPomodoroTimer(container) {
|
||||
var _a, _b, _c, _d, _e;
|
||||
var _a, _b, _c, _d, _e, _f;
|
||||
let mainControlsRow = container.querySelector(".pomodoro-main-controls");
|
||||
if (!mainControlsRow) {
|
||||
mainControlsRow = container.createDiv("pomodoro-main-controls");
|
||||
|
|
@ -4533,12 +4539,16 @@ var PomodoroUIManager = class {
|
|||
(0, import_obsidian12.setIcon)(this.pomodoroSkipBtn, "skip-forward");
|
||||
this.pomodoroSkipBtn.addEventListener("click", () => this.plugin.pomodoroService.skipSession());
|
||||
}
|
||||
if (!this.pomodoroCycleProgressEl || this.pomodoroCycleProgressEl.parentElement !== container) {
|
||||
(_e = this.pomodoroCycleProgressEl) == null ? void 0 : _e.remove();
|
||||
this.pomodoroCycleProgressEl = container.createDiv("pomodoro-cycle-progress");
|
||||
}
|
||||
let settingsPanelContainer = container.querySelector(".pomodoro-settings-panel-container");
|
||||
if (!settingsPanelContainer) {
|
||||
settingsPanelContainer = container.createDiv("pomodoro-settings-panel-container");
|
||||
}
|
||||
if (!this.pomodoroQuickSettingsPanelEl || this.pomodoroQuickSettingsPanelEl.parentElement !== settingsPanelContainer) {
|
||||
(_e = this.pomodoroQuickSettingsPanelEl) == null ? void 0 : _e.remove();
|
||||
(_f = this.pomodoroQuickSettingsPanelEl) == null ? void 0 : _f.remove();
|
||||
this.pomodoroQuickSettingsPanelEl = settingsPanelContainer.createDiv("pomodoro-quick-settings-panel");
|
||||
this.pomodoroQuickSettingsPanelEl.style.display = "none";
|
||||
const createQuickSetting = (labelText, inputType = "number") => {
|
||||
|
|
@ -4553,6 +4563,26 @@ var PomodoroUIManager = class {
|
|||
this.pomodoroQuickLongInput = createQuickSetting("Long Break (min):");
|
||||
this.pomodoroQuickSessionsInput = createQuickSetting("Sessions/Long Break:");
|
||||
const buttonsContainer = this.pomodoroQuickSettingsPanelEl.createDiv({ cls: "pomodoro-quick-settings-buttons" });
|
||||
const overrideContainer = this.pomodoroQuickSettingsPanelEl.createDiv("pomodoro-override-container");
|
||||
const overrideLabel = overrideContainer.createEl("label", { text: "Override time (optional):", cls: "pomodoro-override-label" });
|
||||
const overrideInputsContainer = overrideContainer.createDiv("pomodoro-override-inputs");
|
||||
this.pomodoroUserOverrideHoursInput = overrideInputsContainer.createEl("input", { type: "number", cls: "pomodoro-override-hours" });
|
||||
this.pomodoroUserOverrideHoursInput.setAttr("min", "0");
|
||||
this.pomodoroUserOverrideHoursInput.setAttr("placeholder", "H");
|
||||
this.pomodoroUserOverrideHoursInput.value = String(this.plugin.pluginState.pomodoroUserOverrideHours);
|
||||
const hoursLabel = overrideInputsContainer.createSpan("pomodoro-override-label-small");
|
||||
hoursLabel.setText("h");
|
||||
this.pomodoroUserOverrideMinutesInput = overrideInputsContainer.createEl("input", { type: "number", cls: "pomodoro-override-minutes" });
|
||||
this.pomodoroUserOverrideMinutesInput.setAttr("min", "0");
|
||||
this.pomodoroUserOverrideMinutesInput.setAttr("placeholder", "M");
|
||||
this.pomodoroUserOverrideMinutesInput.value = String(this.plugin.pluginState.pomodoroUserOverrideMinutes);
|
||||
const minutesLabel = overrideInputsContainer.createSpan("pomodoro-override-label-small");
|
||||
minutesLabel.setText("m");
|
||||
const toggleContainer = overrideContainer.createDiv("pomodoro-override-toggle-container");
|
||||
this.pomodoroUserAddToEstimationCheckbox = toggleContainer.createEl("input", { type: "checkbox", cls: "pomodoro-add-to-estimation" });
|
||||
this.pomodoroUserAddToEstimationCheckbox.checked = this.plugin.pluginState.pomodoroUserAddToEstimation;
|
||||
const toggleLabel = toggleContainer.createEl("label", { text: "Add to estimated time", cls: "pomodoro-toggle-label" });
|
||||
toggleLabel.setAttribute("for", "pomodoro-add-to-estimation");
|
||||
const calculateBtn = buttonsContainer.createEl("button", { text: "Calculate Reading Time", cls: "pomodoro-quick-calculate-btn" });
|
||||
calculateBtn.addEventListener("click", async () => {
|
||||
const settingsSaved = this._savePomodoroSettings();
|
||||
|
|
@ -4571,54 +4601,60 @@ var PomodoroUIManager = class {
|
|||
async calculateAndDisplayPomodoroEstimate() {
|
||||
if (!this.plugin || !this.pomodoroCalculationResultEl)
|
||||
return;
|
||||
this.saveUserOverrideSettings();
|
||||
const notesForEstimate = this.plugin.reviewController.getTodayNotes();
|
||||
if (notesForEstimate.length === 0) {
|
||||
const userOverrideHours = this.plugin.pluginState.pomodoroUserOverrideHours || 0;
|
||||
const userOverrideMinutes = this.plugin.pluginState.pomodoroUserOverrideMinutes || 0;
|
||||
const userOverrideTimeInMinutes = userOverrideHours * 60 + userOverrideMinutes;
|
||||
if (notesForEstimate.length === 0 && userOverrideTimeInMinutes === 0) {
|
||||
const activeDate = this.plugin.reviewController.getCurrentReviewDateOverride();
|
||||
const message = activeDate ? `No notes scheduled for ${new Date(activeDate).toLocaleDateString()} to calculate.` : "No notes currently due to calculate.";
|
||||
this.pomodoroCalculationResultEl.setText(message);
|
||||
this.pomodoroCalculationResultEl.style.display = "block";
|
||||
return;
|
||||
}
|
||||
let totalReadingTimeInSeconds = 0;
|
||||
for (const note of notesForEstimate) {
|
||||
totalReadingTimeInSeconds += await this.plugin.reviewScheduleService.estimateReviewTime(note.path);
|
||||
}
|
||||
const totalReadingTimeInMinutes = totalReadingTimeInSeconds / 60;
|
||||
const settings = this.plugin.settings;
|
||||
const workDuration = settings.pomodoroWorkDuration;
|
||||
const shortBreakDuration = settings.pomodoroShortBreakDuration;
|
||||
const longBreakDuration = settings.pomodoroLongBreakDuration;
|
||||
const sessionsUntilLongBreak = settings.pomodoroSessionsUntilLongBreak;
|
||||
let pomodorosNeeded = 0;
|
||||
let sessionsCompletedInCycle = 0;
|
||||
let remainingReadingTimeMinutes = totalReadingTimeInMinutes;
|
||||
let totalBreakTimeInMinutes = 0;
|
||||
if (totalReadingTimeInMinutes === 0) {
|
||||
this.pomodoroCalculationResultEl.setText("Estimated reading time is 0 minutes.");
|
||||
const result = await this.plugin.pomodoroService.calculateEstimationFromNotes(notesForEstimate);
|
||||
if (!result) {
|
||||
this.pomodoroCalculationResultEl.setText("Unable to calculate estimation.");
|
||||
this.pomodoroCalculationResultEl.style.display = "block";
|
||||
return;
|
||||
}
|
||||
while (remainingReadingTimeMinutes > 0) {
|
||||
pomodorosNeeded++;
|
||||
remainingReadingTimeMinutes -= workDuration;
|
||||
sessionsCompletedInCycle++;
|
||||
if (remainingReadingTimeMinutes <= 0)
|
||||
break;
|
||||
if (sessionsCompletedInCycle >= sessionsUntilLongBreak) {
|
||||
totalBreakTimeInMinutes += longBreakDuration;
|
||||
sessionsCompletedInCycle = 0;
|
||||
} else {
|
||||
totalBreakTimeInMinutes += shortBreakDuration;
|
||||
}
|
||||
}
|
||||
const totalTimeWithBreaksMinutes = pomodorosNeeded * workDuration + totalBreakTimeInMinutes;
|
||||
const { totalReadingTimeInSeconds, totalReadingTimeInMinutes, pomodorosNeeded, totalTimeWithBreaksMinutes } = result;
|
||||
const addToEstimation = this.plugin.pluginState.pomodoroUserAddToEstimation || false;
|
||||
const formattedTotalReadingTime = EstimationUtils.formatTime(totalReadingTimeInSeconds);
|
||||
const formattedTotalTimeWithBreaks = EstimationUtils.formatTime(Math.ceil(totalTimeWithBreaksMinutes * 60));
|
||||
this.pomodoroCalculationResultEl.empty();
|
||||
this.pomodoroCalculationResultEl.createEl("p", { text: `Estimated reading time for ${notesForEstimate.length} note(s) in current view: ${formattedTotalReadingTime}.` });
|
||||
if (notesForEstimate.length > 0 && totalReadingTimeInSeconds > 0 && (!userOverrideTimeInMinutes || addToEstimation)) {
|
||||
let baseReadingTimeInSeconds = 0;
|
||||
for (const note of notesForEstimate) {
|
||||
baseReadingTimeInSeconds += await this.plugin.reviewScheduleService.estimateReviewTime(note.path);
|
||||
}
|
||||
const formattedBaseReadingTime = EstimationUtils.formatTime(baseReadingTimeInSeconds);
|
||||
this.pomodoroCalculationResultEl.createEl("p", { text: `Base reading time for ${notesForEstimate.length} note(s): ${formattedBaseReadingTime}.` });
|
||||
} else if (notesForEstimate.length === 0 && userOverrideTimeInMinutes > 0) {
|
||||
this.pomodoroCalculationResultEl.createEl("p", { text: `Using override time only (no notes).` });
|
||||
}
|
||||
if (userOverrideTimeInMinutes > 0) {
|
||||
const overrideText = addToEstimation ? `Added ${userOverrideHours}h ${userOverrideMinutes}m override time.` : `Using ${userOverrideHours}h ${userOverrideMinutes}m override time (replacing estimate).`;
|
||||
this.pomodoroCalculationResultEl.createEl("p", { text: overrideText, cls: "pomodoro-override-info" });
|
||||
}
|
||||
this.pomodoroCalculationResultEl.createEl("p", { text: `Requires ~${pomodorosNeeded} Pomodoro work session(s).` });
|
||||
this.pomodoroCalculationResultEl.createEl("p", { text: `Total time with breaks: ~${formattedTotalTimeWithBreaks}.` });
|
||||
this.pomodoroCalculationResultEl.style.display = "block";
|
||||
this.updateCycleProgressDisplay();
|
||||
}
|
||||
/**
|
||||
* Saves user override settings to plugin state
|
||||
*/
|
||||
saveUserOverrideSettings() {
|
||||
var _a, _b, _c;
|
||||
const hours = parseInt(((_a = this.pomodoroUserOverrideHoursInput) == null ? void 0 : _a.value) || "0");
|
||||
const minutes = parseInt(((_b = this.pomodoroUserOverrideMinutesInput) == null ? void 0 : _b.value) || "0");
|
||||
const addToEstimation = ((_c = this.pomodoroUserAddToEstimationCheckbox) == null ? void 0 : _c.checked) || false;
|
||||
this.plugin.pluginState.pomodoroUserOverrideHours = hours;
|
||||
this.plugin.pluginState.pomodoroUserOverrideMinutes = minutes;
|
||||
this.plugin.pluginState.pomodoroUserAddToEstimation = addToEstimation;
|
||||
this.plugin.savePluginData();
|
||||
}
|
||||
/**
|
||||
* Updates the Pomodoro UI based on the current state from PomodoroService.
|
||||
|
|
@ -4704,6 +4740,46 @@ var PomodoroUIManager = class {
|
|||
if (this.pomodoroCalculationResultEl && ((_a = this.pomodoroQuickSettingsPanelEl) == null ? void 0 : _a.style.display) === "none") {
|
||||
this.pomodoroCalculationResultEl.style.display = "none";
|
||||
}
|
||||
this.updateCycleProgressDisplay();
|
||||
}
|
||||
/**
|
||||
* Updates the cycle progress display based on current state
|
||||
*/
|
||||
updateCycleProgressDisplay() {
|
||||
if (!this.pomodoroCycleProgressEl)
|
||||
return;
|
||||
const cycleProgress = this.plugin.pomodoroService.getCycleProgress();
|
||||
if (cycleProgress) {
|
||||
const { current, total, workSessionsRemaining, totalWorkSessions, totalTimeMinutes } = cycleProgress;
|
||||
const completedSessions = totalWorkSessions - workSessionsRemaining;
|
||||
const totalHours = Math.floor(totalTimeMinutes / 60);
|
||||
const totalMinutes = Math.round(totalTimeMinutes % 60);
|
||||
const timeString = totalHours > 0 ? `${totalHours}H/${totalMinutes}M` : `${totalMinutes}M`;
|
||||
this.pomodoroCycleProgressEl.setText(`Cycles ${current}/${total} - Sessions ${completedSessions}/${totalWorkSessions} - ${timeString}`);
|
||||
this.pomodoroCycleProgressEl.style.display = "";
|
||||
this.pomodoroCycleProgressEl.addClass("cycle-active");
|
||||
} else {
|
||||
this.pomodoroCycleProgressEl.style.display = "none";
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Format time in seconds to a readable string
|
||||
*/
|
||||
formatTime(totalSeconds) {
|
||||
const hours = Math.floor(totalSeconds / 3600);
|
||||
const minutes = Math.floor(totalSeconds % 3600 / 60);
|
||||
if (hours > 0) {
|
||||
return `${hours}h ${minutes}m`;
|
||||
} else {
|
||||
return `${minutes}m`;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Calculate and display estimation for current notes
|
||||
*/
|
||||
async calculateAndDisplayEstimation() {
|
||||
const notesForEstimate = this.plugin.reviewController.getTodayNotes();
|
||||
await this.plugin.pomodoroService.calculateEstimationFromNotes(notesForEstimate);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -5174,6 +5250,26 @@ var ListViewRenderer = class {
|
|||
// statsCountEl.setText(`${dueNotesForStats.length} notes - ${EstimationUtils.formatTime(totalTime)}${overdueNotes.length > 0 ? ` (${overdueNotes.length} overdue)` : ''}`);
|
||||
// }
|
||||
async _ensureAndUpdateReviewButtonsSection(container, notesForDisplay, selectedNotes) {
|
||||
let pomodoroContainer = container.querySelector(".sidebar-pomodoro-section");
|
||||
if (!pomodoroContainer) {
|
||||
pomodoroContainer = container.createDiv("sidebar-pomodoro-section");
|
||||
const pomodoroSectionContainerEl = pomodoroContainer.createDiv("sidebar-pomodoro-button-container");
|
||||
}
|
||||
if (this.pomodoroUIManager && pomodoroContainer) {
|
||||
const pomodoroSectionContainerEl = pomodoroContainer.querySelector(".sidebar-pomodoro-button-container");
|
||||
if (pomodoroSectionContainerEl) {
|
||||
this.pomodoroUIManager.attachAndRender(pomodoroSectionContainerEl);
|
||||
if (this.plugin.settings.pomodoroEnabled) {
|
||||
pomodoroContainer.style.display = "";
|
||||
this.pomodoroUIManager.showPomodoroSection(true);
|
||||
this.pomodoroUIManager.updatePomodoroUI();
|
||||
this.pomodoroUIManager.calculateAndDisplayEstimation();
|
||||
} else {
|
||||
pomodoroContainer.style.display = "none";
|
||||
this.pomodoroUIManager.showPomodoroSection(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
let reviewButtonsContainer = container.querySelector(".review-buttons-container");
|
||||
if (notesForDisplay.length > 0) {
|
||||
if (!reviewButtonsContainer) {
|
||||
|
|
@ -5187,7 +5283,6 @@ var ListViewRenderer = class {
|
|||
nextNoteBtn.addEventListener("click", () => {
|
||||
this.plugin.reviewController.navigateToNextNote();
|
||||
});
|
||||
reviewButtonsContainer.createDiv("sidebar-pomodoro-button-container");
|
||||
const reviewCurrentBtn = reviewButtonsContainer.createEl("button", { text: "Review Current Note", title: "Review the currently open note if it's due", cls: "review-all-button" });
|
||||
reviewCurrentBtn.addEventListener("click", () => {
|
||||
this.plugin.reviewController.reviewCurrentNote();
|
||||
|
|
@ -5204,16 +5299,6 @@ var ListViewRenderer = class {
|
|||
}
|
||||
}
|
||||
reviewButtonsContainer.style.display = "";
|
||||
const pomodoroSectionContainerEl = reviewButtonsContainer.querySelector(".sidebar-pomodoro-button-container");
|
||||
if (this.pomodoroUIManager && pomodoroSectionContainerEl) {
|
||||
this.pomodoroUIManager.attachAndRender(pomodoroSectionContainerEl);
|
||||
if (this.plugin.settings.pomodoroEnabled) {
|
||||
this.pomodoroUIManager.showPomodoroSection(true);
|
||||
this.pomodoroUIManager.updatePomodoroUI();
|
||||
} else {
|
||||
this.pomodoroUIManager.showPomodoroSection(false);
|
||||
}
|
||||
}
|
||||
let bulkActionButtons = container.querySelector(".review-bulk-actions");
|
||||
if (!bulkActionButtons) {
|
||||
bulkActionButtons = container.createDiv("review-bulk-actions");
|
||||
|
|
@ -6447,7 +6532,16 @@ var DEFAULT_PLUGIN_STATE_DATA = {
|
|||
// Default to work duration
|
||||
pomodoroSessionsCompletedInCycle: 0,
|
||||
pomodoroIsRunning: false,
|
||||
pomodoroEndTimeMs: null
|
||||
pomodoroEndTimeMs: null,
|
||||
// Pomodoro Estimation and Cycle Tracking Defaults
|
||||
pomodoroEstimatedTotalCycles: null,
|
||||
pomodoroEstimatedWorkSessions: null,
|
||||
pomodoroIsEstimationActive: false,
|
||||
pomodoroUserHasModifiedSettings: false,
|
||||
// User Override Time Settings Defaults
|
||||
pomodoroUserOverrideHours: 0,
|
||||
pomodoroUserOverrideMinutes: 0,
|
||||
pomodoroUserAddToEstimation: false
|
||||
};
|
||||
var DEFAULT_APP_DATA = {
|
||||
settings: DEFAULT_SETTINGS,
|
||||
|
|
@ -6501,7 +6595,7 @@ var SpaceforgeSettingTab = class extends import_obsidian17.PluginSettingTab {
|
|||
const actionsContainer = containerEl.createEl("div", { cls: "sf-settings-actions" });
|
||||
const exportBtn = actionsContainer.createEl("button", { text: "Export all data" });
|
||||
exportBtn.addEventListener("click", () => {
|
||||
var _a;
|
||||
var _a, _b, _c, _d, _e, _f, _g, _h;
|
||||
const pluginStateToExport = {
|
||||
schedules: this.plugin.reviewScheduleService.schedules,
|
||||
history: this.plugin.reviewHistoryService.history,
|
||||
|
|
@ -6515,8 +6609,15 @@ var SpaceforgeSettingTab = class extends import_obsidian17.PluginSettingTab {
|
|||
pomodoroTimeLeftInSeconds: this.plugin.pluginState.pomodoroTimeLeftInSeconds,
|
||||
pomodoroSessionsCompletedInCycle: this.plugin.pluginState.pomodoroSessionsCompletedInCycle,
|
||||
pomodoroIsRunning: this.plugin.pluginState.pomodoroIsRunning,
|
||||
pomodoroEndTimeMs: (_a = this.plugin.pluginState.pomodoroEndTimeMs) != null ? _a : null
|
||||
pomodoroEndTimeMs: (_a = this.plugin.pluginState.pomodoroEndTimeMs) != null ? _a : null,
|
||||
// Add the missing field
|
||||
pomodoroEstimatedTotalCycles: (_b = this.plugin.pluginState.pomodoroEstimatedTotalCycles) != null ? _b : null,
|
||||
pomodoroEstimatedWorkSessions: (_c = this.plugin.pluginState.pomodoroEstimatedWorkSessions) != null ? _c : null,
|
||||
pomodoroIsEstimationActive: (_d = this.plugin.pluginState.pomodoroIsEstimationActive) != null ? _d : false,
|
||||
pomodoroUserHasModifiedSettings: (_e = this.plugin.pluginState.pomodoroUserHasModifiedSettings) != null ? _e : false,
|
||||
pomodoroUserOverrideHours: (_f = this.plugin.pluginState.pomodoroUserOverrideHours) != null ? _f : 0,
|
||||
pomodoroUserOverrideMinutes: (_g = this.plugin.pluginState.pomodoroUserOverrideMinutes) != null ? _g : 0,
|
||||
pomodoroUserAddToEstimation: (_h = this.plugin.pluginState.pomodoroUserAddToEstimation) != null ? _h : false
|
||||
};
|
||||
const dataToExport = {
|
||||
settings: this.plugin.settings,
|
||||
|
|
@ -9570,10 +9671,21 @@ var PomodoroService = class {
|
|||
return `${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}`;
|
||||
}
|
||||
updateDurations(work, short, long, sessions) {
|
||||
const currentWork = this.settings.pomodoroWorkDuration;
|
||||
const currentShort = this.settings.pomodoroShortBreakDuration;
|
||||
const currentLong = this.settings.pomodoroLongBreakDuration;
|
||||
const currentSessions = this.settings.pomodoroSessionsUntilLongBreak;
|
||||
const userChangedSettings = work !== currentWork || short !== currentShort || long !== currentLong || sessions !== currentSessions;
|
||||
this.settings.pomodoroWorkDuration = work;
|
||||
this.settings.pomodoroShortBreakDuration = short;
|
||||
this.settings.pomodoroLongBreakDuration = long;
|
||||
this.settings.pomodoroSessionsUntilLongBreak = sessions;
|
||||
if (userChangedSettings) {
|
||||
this.state.pomodoroUserHasModifiedSettings = true;
|
||||
this.state.pomodoroIsEstimationActive = false;
|
||||
this.state.pomodoroEstimatedTotalCycles = null;
|
||||
this.state.pomodoroEstimatedWorkSessions = null;
|
||||
}
|
||||
const activeModesForDurationUpdate = ["work", "shortBreak", "longBreak"];
|
||||
if (!this.state.pomodoroIsRunning && activeModesForDurationUpdate.includes(this.state.pomodoroCurrentMode)) {
|
||||
this.resetTimeForMode(this.state.pomodoroCurrentMode);
|
||||
|
|
@ -9581,6 +9693,126 @@ var PomodoroService = class {
|
|||
this.plugin.savePluginData();
|
||||
this.notifyUpdate();
|
||||
}
|
||||
/**
|
||||
* Calculate and set estimation based on reading time
|
||||
*/
|
||||
async calculateEstimationFromNotes(notes) {
|
||||
const userOverrideHours = this.state.pomodoroUserOverrideHours || 0;
|
||||
const userOverrideMinutes = this.state.pomodoroUserOverrideMinutes || 0;
|
||||
const userOverrideTimeInMinutes = userOverrideHours * 60 + userOverrideMinutes;
|
||||
const addToEstimation = this.state.pomodoroUserAddToEstimation || false;
|
||||
let totalReadingTimeInSeconds = 0;
|
||||
let totalReadingTimeInMinutes = 0;
|
||||
if (notes.length > 0) {
|
||||
for (const note of notes) {
|
||||
totalReadingTimeInSeconds += await this.plugin.reviewScheduleService.estimateReviewTime(note.path);
|
||||
}
|
||||
totalReadingTimeInMinutes = totalReadingTimeInSeconds / 60;
|
||||
}
|
||||
if (userOverrideTimeInMinutes > 0) {
|
||||
if (addToEstimation) {
|
||||
totalReadingTimeInMinutes += userOverrideTimeInMinutes;
|
||||
} else {
|
||||
totalReadingTimeInMinutes = userOverrideTimeInMinutes;
|
||||
totalReadingTimeInSeconds = userOverrideTimeInMinutes * 60;
|
||||
}
|
||||
}
|
||||
if (notes.length === 0 && userOverrideTimeInMinutes === 0) {
|
||||
this.state.pomodoroIsEstimationActive = false;
|
||||
this.state.pomodoroEstimatedTotalCycles = null;
|
||||
this.state.pomodoroEstimatedWorkSessions = null;
|
||||
this.notifyUpdate();
|
||||
return null;
|
||||
}
|
||||
const settings = this.settings;
|
||||
const workDuration = settings.pomodoroWorkDuration;
|
||||
const shortBreakDuration = settings.pomodoroShortBreakDuration;
|
||||
const longBreakDuration = settings.pomodoroLongBreakDuration;
|
||||
const sessionsUntilLongBreak = settings.pomodoroSessionsUntilLongBreak;
|
||||
if (totalReadingTimeInMinutes === 0 || workDuration === 0) {
|
||||
this.state.pomodoroIsEstimationActive = false;
|
||||
this.state.pomodoroEstimatedTotalCycles = null;
|
||||
this.state.pomodoroEstimatedWorkSessions = null;
|
||||
this.notifyUpdate();
|
||||
return null;
|
||||
}
|
||||
let pomodorosNeeded = 0;
|
||||
let sessionsCompletedInCycle = 0;
|
||||
let remainingReadingTimeMinutes = totalReadingTimeInMinutes;
|
||||
let totalBreakTimeInMinutes = 0;
|
||||
while (remainingReadingTimeMinutes > 0) {
|
||||
pomodorosNeeded++;
|
||||
remainingReadingTimeMinutes -= workDuration;
|
||||
sessionsCompletedInCycle++;
|
||||
if (remainingReadingTimeMinutes <= 0)
|
||||
break;
|
||||
if (sessionsCompletedInCycle >= sessionsUntilLongBreak) {
|
||||
totalBreakTimeInMinutes += longBreakDuration;
|
||||
sessionsCompletedInCycle = 0;
|
||||
} else {
|
||||
totalBreakTimeInMinutes += shortBreakDuration;
|
||||
}
|
||||
}
|
||||
this.state.pomodoroEstimatedTotalCycles = Math.ceil(pomodorosNeeded / sessionsUntilLongBreak);
|
||||
this.state.pomodoroEstimatedWorkSessions = pomodorosNeeded;
|
||||
this.state.pomodoroIsEstimationActive = true;
|
||||
this.plugin.savePluginData();
|
||||
this.notifyUpdate();
|
||||
return {
|
||||
totalReadingTimeInSeconds,
|
||||
totalReadingTimeInMinutes,
|
||||
pomodorosNeeded,
|
||||
totalTimeWithBreaksMinutes: pomodorosNeeded * workDuration + totalBreakTimeInMinutes
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Get current cycle progress information
|
||||
*/
|
||||
getCycleProgress() {
|
||||
if (!this.state.pomodoroIsEstimationActive || !this.state.pomodoroEstimatedWorkSessions) {
|
||||
return null;
|
||||
}
|
||||
const currentCycle = Math.floor(this.state.pomodoroSessionsCompletedInCycle / this.settings.pomodoroSessionsUntilLongBreak) + 1;
|
||||
const totalCycles = this.state.pomodoroEstimatedTotalCycles || 1;
|
||||
const workSessionsRemaining = Math.max(0, this.state.pomodoroEstimatedWorkSessions - this.state.pomodoroSessionsCompletedInCycle);
|
||||
const totalWorkSessions = this.state.pomodoroEstimatedWorkSessions;
|
||||
const workDuration = this.settings.pomodoroWorkDuration;
|
||||
const shortBreakDuration = this.settings.pomodoroShortBreakDuration;
|
||||
const longBreakDuration = this.settings.pomodoroLongBreakDuration;
|
||||
const sessionsUntilLongBreak = this.settings.pomodoroSessionsUntilLongBreak;
|
||||
let totalBreakTime = 0;
|
||||
let sessionsInCycle = 0;
|
||||
for (let i = 0; i < totalWorkSessions; i++) {
|
||||
sessionsInCycle++;
|
||||
if (i < totalWorkSessions - 1) {
|
||||
if (sessionsInCycle >= sessionsUntilLongBreak) {
|
||||
totalBreakTime += longBreakDuration;
|
||||
sessionsInCycle = 0;
|
||||
} else {
|
||||
totalBreakTime += shortBreakDuration;
|
||||
}
|
||||
}
|
||||
}
|
||||
const totalTimeMinutes = totalWorkSessions * workDuration + totalBreakTime;
|
||||
return {
|
||||
current: currentCycle,
|
||||
total: totalCycles,
|
||||
workSessionsRemaining,
|
||||
totalWorkSessions,
|
||||
totalTimeMinutes
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Reset estimation state (call when user wants to clear estimation)
|
||||
*/
|
||||
resetEstimation() {
|
||||
this.state.pomodoroIsEstimationActive = false;
|
||||
this.state.pomodoroEstimatedTotalCycles = null;
|
||||
this.state.pomodoroEstimatedWorkSessions = null;
|
||||
this.state.pomodoroUserHasModifiedSettings = false;
|
||||
this.plugin.savePluginData();
|
||||
this.notifyUpdate();
|
||||
}
|
||||
// --- Internal Logic ---
|
||||
startTimerInterval() {
|
||||
if (this.timerInterval !== null) {
|
||||
|
|
@ -10073,7 +10305,7 @@ var SpaceforgePlugin = class extends import_obsidian26.Plugin {
|
|||
}
|
||||
}
|
||||
async savePluginData() {
|
||||
var _a, _b;
|
||||
var _a, _b, _c, _d;
|
||||
try {
|
||||
if (!this.settings || typeof this.settings !== "object") {
|
||||
this.settings = JSON.parse(JSON.stringify(DEFAULT_SETTINGS));
|
||||
|
|
@ -10097,6 +10329,13 @@ var SpaceforgePlugin = class extends import_obsidian26.Plugin {
|
|||
pomodoroIsRunning: typeof this.pluginState.pomodoroIsRunning === "boolean" ? this.pluginState.pomodoroIsRunning : DEFAULT_PLUGIN_STATE_DATA.pomodoroIsRunning,
|
||||
pomodoroEndTimeMs: (_b = this.pluginState.pomodoroEndTimeMs) != null ? _b : null,
|
||||
// Add the missing field
|
||||
pomodoroEstimatedTotalCycles: (_c = this.pluginState.pomodoroEstimatedTotalCycles) != null ? _c : DEFAULT_PLUGIN_STATE_DATA.pomodoroEstimatedTotalCycles,
|
||||
pomodoroEstimatedWorkSessions: (_d = this.pluginState.pomodoroEstimatedWorkSessions) != null ? _d : DEFAULT_PLUGIN_STATE_DATA.pomodoroEstimatedWorkSessions,
|
||||
pomodoroIsEstimationActive: typeof this.pluginState.pomodoroIsEstimationActive === "boolean" ? this.pluginState.pomodoroIsEstimationActive : DEFAULT_PLUGIN_STATE_DATA.pomodoroIsEstimationActive,
|
||||
pomodoroUserHasModifiedSettings: typeof this.pluginState.pomodoroUserHasModifiedSettings === "boolean" ? this.pluginState.pomodoroUserHasModifiedSettings : DEFAULT_PLUGIN_STATE_DATA.pomodoroUserHasModifiedSettings,
|
||||
pomodoroUserOverrideHours: typeof this.pluginState.pomodoroUserOverrideHours === "number" ? this.pluginState.pomodoroUserOverrideHours : DEFAULT_PLUGIN_STATE_DATA.pomodoroUserOverrideHours,
|
||||
pomodoroUserOverrideMinutes: typeof this.pluginState.pomodoroUserOverrideMinutes === "number" ? this.pluginState.pomodoroUserOverrideMinutes : DEFAULT_PLUGIN_STATE_DATA.pomodoroUserOverrideMinutes,
|
||||
pomodoroUserAddToEstimation: typeof this.pluginState.pomodoroUserAddToEstimation === "boolean" ? this.pluginState.pomodoroUserAddToEstimation : DEFAULT_PLUGIN_STATE_DATA.pomodoroUserAddToEstimation,
|
||||
version: this.manifest.version
|
||||
};
|
||||
this.pluginState = currentPluginState;
|
||||
|
|
|
|||
7
main.ts
7
main.ts
|
|
@ -464,6 +464,13 @@ export default class SpaceforgePlugin extends Plugin {
|
|||
pomodoroSessionsCompletedInCycle: this.pluginState.pomodoroSessionsCompletedInCycle || DEFAULT_PLUGIN_STATE_DATA.pomodoroSessionsCompletedInCycle,
|
||||
pomodoroIsRunning: typeof this.pluginState.pomodoroIsRunning === 'boolean' ? this.pluginState.pomodoroIsRunning : DEFAULT_PLUGIN_STATE_DATA.pomodoroIsRunning,
|
||||
pomodoroEndTimeMs: this.pluginState.pomodoroEndTimeMs ?? null, // Add the missing field
|
||||
pomodoroEstimatedTotalCycles: this.pluginState.pomodoroEstimatedTotalCycles ?? DEFAULT_PLUGIN_STATE_DATA.pomodoroEstimatedTotalCycles,
|
||||
pomodoroEstimatedWorkSessions: this.pluginState.pomodoroEstimatedWorkSessions ?? DEFAULT_PLUGIN_STATE_DATA.pomodoroEstimatedWorkSessions,
|
||||
pomodoroIsEstimationActive: typeof this.pluginState.pomodoroIsEstimationActive === 'boolean' ? this.pluginState.pomodoroIsEstimationActive : DEFAULT_PLUGIN_STATE_DATA.pomodoroIsEstimationActive,
|
||||
pomodoroUserHasModifiedSettings: typeof this.pluginState.pomodoroUserHasModifiedSettings === 'boolean' ? this.pluginState.pomodoroUserHasModifiedSettings : DEFAULT_PLUGIN_STATE_DATA.pomodoroUserHasModifiedSettings,
|
||||
pomodoroUserOverrideHours: typeof this.pluginState.pomodoroUserOverrideHours === 'number' ? this.pluginState.pomodoroUserOverrideHours : DEFAULT_PLUGIN_STATE_DATA.pomodoroUserOverrideHours,
|
||||
pomodoroUserOverrideMinutes: typeof this.pluginState.pomodoroUserOverrideMinutes === 'number' ? this.pluginState.pomodoroUserOverrideMinutes : DEFAULT_PLUGIN_STATE_DATA.pomodoroUserOverrideMinutes,
|
||||
pomodoroUserAddToEstimation: typeof this.pluginState.pomodoroUserAddToEstimation === 'boolean' ? this.pluginState.pomodoroUserAddToEstimation : DEFAULT_PLUGIN_STATE_DATA.pomodoroUserAddToEstimation,
|
||||
version: this.manifest.version,
|
||||
};
|
||||
this.pluginState = currentPluginState; // Update the live pluginState
|
||||
|
|
|
|||
|
|
@ -23,6 +23,17 @@ export interface PluginStateData {
|
|||
pomodoroSessionsCompletedInCycle: number;
|
||||
pomodoroIsRunning: boolean;
|
||||
pomodoroEndTimeMs: number | null; // Timestamp when the current session ends
|
||||
|
||||
// Pomodoro Estimation and Cycle Tracking
|
||||
pomodoroEstimatedTotalCycles: number | null; // Total cycles calculated from reading time
|
||||
pomodoroEstimatedWorkSessions: number | null; // Total work sessions calculated
|
||||
pomodoroIsEstimationActive: boolean; // Whether estimation is currently active (not overridden by user)
|
||||
pomodoroUserHasModifiedSettings: boolean; // Whether user has manually changed H/M settings
|
||||
|
||||
// User Override Time Settings
|
||||
pomodoroUserOverrideHours: number; // User-specified hours for override
|
||||
pomodoroUserOverrideMinutes: number; // User-specified minutes for override
|
||||
pomodoroUserAddToEstimation: boolean; // Whether to add user time to estimation or replace it
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -44,6 +55,17 @@ export const DEFAULT_PLUGIN_STATE_DATA: PluginStateData = {
|
|||
pomodoroSessionsCompletedInCycle: 0,
|
||||
pomodoroIsRunning: false,
|
||||
pomodoroEndTimeMs: null,
|
||||
|
||||
// Pomodoro Estimation and Cycle Tracking Defaults
|
||||
pomodoroEstimatedTotalCycles: null,
|
||||
pomodoroEstimatedWorkSessions: null,
|
||||
pomodoroIsEstimationActive: false,
|
||||
pomodoroUserHasModifiedSettings: false,
|
||||
|
||||
// User Override Time Settings Defaults
|
||||
pomodoroUserOverrideHours: 0,
|
||||
pomodoroUserOverrideMinutes: 0,
|
||||
pomodoroUserAddToEstimation: false,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
3
note.md
Normal file
3
note.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
bug postpone all postpones all notes not just one note. from that specific days on entry.
|
||||
change due date red color to something more subtle
|
||||
|
||||
|
|
@ -94,11 +94,27 @@ export class PomodoroService {
|
|||
}
|
||||
|
||||
public updateDurations(work: number, short: number, long: number, sessions: number): void {
|
||||
// Check if user is modifying from the current settings (indicating manual override)
|
||||
const currentWork = this.settings.pomodoroWorkDuration;
|
||||
const currentShort = this.settings.pomodoroShortBreakDuration;
|
||||
const currentLong = this.settings.pomodoroLongBreakDuration;
|
||||
const currentSessions = this.settings.pomodoroSessionsUntilLongBreak;
|
||||
|
||||
const userChangedSettings = work !== currentWork || short !== currentShort || long !== currentLong || sessions !== currentSessions;
|
||||
|
||||
this.settings.pomodoroWorkDuration = work;
|
||||
this.settings.pomodoroShortBreakDuration = short;
|
||||
this.settings.pomodoroLongBreakDuration = long;
|
||||
this.settings.pomodoroSessionsUntilLongBreak = sessions;
|
||||
|
||||
// If user manually changed settings, mark as modified and deactivate estimation
|
||||
if (userChangedSettings) {
|
||||
this.state.pomodoroUserHasModifiedSettings = true;
|
||||
this.state.pomodoroIsEstimationActive = false;
|
||||
this.state.pomodoroEstimatedTotalCycles = null;
|
||||
this.state.pomodoroEstimatedWorkSessions = null;
|
||||
}
|
||||
|
||||
// If current session is not running and its mode (which is an active timed mode) had its duration changed, update its timeLeft
|
||||
const activeModesForDurationUpdate: PomodoroMode[] = ['work', 'shortBreak', 'longBreak'];
|
||||
if (!this.state.pomodoroIsRunning && activeModesForDurationUpdate.includes(this.state.pomodoroCurrentMode)) {
|
||||
|
|
@ -108,6 +124,165 @@ export class PomodoroService {
|
|||
this.notifyUpdate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate and set estimation based on reading time
|
||||
*/
|
||||
public async calculateEstimationFromNotes(notes: any[]): Promise<{
|
||||
totalReadingTimeInSeconds: number;
|
||||
totalReadingTimeInMinutes: number;
|
||||
pomodorosNeeded: number;
|
||||
totalTimeWithBreaksMinutes: number;
|
||||
} | null> {
|
||||
// Apply user override if specified
|
||||
const userOverrideHours = this.state.pomodoroUserOverrideHours || 0;
|
||||
const userOverrideMinutes = this.state.pomodoroUserOverrideMinutes || 0;
|
||||
const userOverrideTimeInMinutes = (userOverrideHours * 60) + userOverrideMinutes;
|
||||
const addToEstimation = this.state.pomodoroUserAddToEstimation || false;
|
||||
|
||||
let totalReadingTimeInSeconds = 0;
|
||||
let totalReadingTimeInMinutes = 0;
|
||||
|
||||
// Calculate base reading time from notes
|
||||
if (notes.length > 0) {
|
||||
for (const note of notes) {
|
||||
totalReadingTimeInSeconds += await this.plugin.reviewScheduleService.estimateReviewTime(note.path);
|
||||
}
|
||||
totalReadingTimeInMinutes = totalReadingTimeInSeconds / 60;
|
||||
}
|
||||
|
||||
// Apply user override
|
||||
if (userOverrideTimeInMinutes > 0) {
|
||||
if (addToEstimation) {
|
||||
totalReadingTimeInMinutes += userOverrideTimeInMinutes;
|
||||
} else {
|
||||
totalReadingTimeInMinutes = userOverrideTimeInMinutes;
|
||||
totalReadingTimeInSeconds = userOverrideTimeInMinutes * 60; // Update seconds too for consistency
|
||||
}
|
||||
}
|
||||
|
||||
// If no notes and no override, return null
|
||||
if (notes.length === 0 && userOverrideTimeInMinutes === 0) {
|
||||
this.state.pomodoroIsEstimationActive = false;
|
||||
this.state.pomodoroEstimatedTotalCycles = null;
|
||||
this.state.pomodoroEstimatedWorkSessions = null;
|
||||
this.notifyUpdate();
|
||||
return null;
|
||||
}
|
||||
|
||||
const settings = this.settings;
|
||||
const workDuration = settings.pomodoroWorkDuration;
|
||||
const shortBreakDuration = settings.pomodoroShortBreakDuration;
|
||||
const longBreakDuration = settings.pomodoroLongBreakDuration;
|
||||
const sessionsUntilLongBreak = settings.pomodoroSessionsUntilLongBreak;
|
||||
|
||||
if (totalReadingTimeInMinutes === 0 || workDuration === 0) {
|
||||
this.state.pomodoroIsEstimationActive = false;
|
||||
this.state.pomodoroEstimatedTotalCycles = null;
|
||||
this.state.pomodoroEstimatedWorkSessions = null;
|
||||
this.notifyUpdate();
|
||||
return null;
|
||||
}
|
||||
|
||||
let pomodorosNeeded = 0;
|
||||
let sessionsCompletedInCycle = 0;
|
||||
let remainingReadingTimeMinutes = totalReadingTimeInMinutes;
|
||||
let totalBreakTimeInMinutes = 0;
|
||||
|
||||
while (remainingReadingTimeMinutes > 0) {
|
||||
pomodorosNeeded++;
|
||||
remainingReadingTimeMinutes -= workDuration;
|
||||
sessionsCompletedInCycle++;
|
||||
|
||||
if (remainingReadingTimeMinutes <= 0) break;
|
||||
|
||||
if (sessionsCompletedInCycle >= sessionsUntilLongBreak) {
|
||||
totalBreakTimeInMinutes += longBreakDuration;
|
||||
sessionsCompletedInCycle = 0;
|
||||
} else {
|
||||
totalBreakTimeInMinutes += shortBreakDuration;
|
||||
}
|
||||
}
|
||||
|
||||
// Always update estimation when calculate is called (this resets the estimation)
|
||||
this.state.pomodoroEstimatedTotalCycles = Math.ceil(pomodorosNeeded / sessionsUntilLongBreak);
|
||||
this.state.pomodoroEstimatedWorkSessions = pomodorosNeeded;
|
||||
this.state.pomodoroIsEstimationActive = true;
|
||||
|
||||
this.plugin.savePluginData();
|
||||
this.notifyUpdate();
|
||||
|
||||
// Return calculation results for UI display
|
||||
return {
|
||||
totalReadingTimeInSeconds,
|
||||
totalReadingTimeInMinutes,
|
||||
pomodorosNeeded,
|
||||
totalTimeWithBreaksMinutes: (pomodorosNeeded * workDuration) + totalBreakTimeInMinutes
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current cycle progress information
|
||||
*/
|
||||
public getCycleProgress(): {
|
||||
current: number;
|
||||
total: number;
|
||||
workSessionsRemaining: number;
|
||||
totalWorkSessions: number;
|
||||
totalTimeMinutes: number;
|
||||
} | null {
|
||||
if (!this.state.pomodoroIsEstimationActive || !this.state.pomodoroEstimatedWorkSessions) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const currentCycle = Math.floor(this.state.pomodoroSessionsCompletedInCycle / this.settings.pomodoroSessionsUntilLongBreak) + 1;
|
||||
const totalCycles = this.state.pomodoroEstimatedTotalCycles || 1;
|
||||
const workSessionsRemaining = Math.max(0, this.state.pomodoroEstimatedWorkSessions - this.state.pomodoroSessionsCompletedInCycle);
|
||||
const totalWorkSessions = this.state.pomodoroEstimatedWorkSessions;
|
||||
|
||||
// Calculate total time including breaks
|
||||
const workDuration = this.settings.pomodoroWorkDuration;
|
||||
const shortBreakDuration = this.settings.pomodoroShortBreakDuration;
|
||||
const longBreakDuration = this.settings.pomodoroLongBreakDuration;
|
||||
const sessionsUntilLongBreak = this.settings.pomodoroSessionsUntilLongBreak;
|
||||
|
||||
let totalBreakTime = 0;
|
||||
let sessionsInCycle = 0;
|
||||
|
||||
for (let i = 0; i < totalWorkSessions; i++) {
|
||||
sessionsInCycle++;
|
||||
if (i < totalWorkSessions - 1) { // Don't add break after last session
|
||||
if (sessionsInCycle >= sessionsUntilLongBreak) {
|
||||
totalBreakTime += longBreakDuration;
|
||||
sessionsInCycle = 0;
|
||||
} else {
|
||||
totalBreakTime += shortBreakDuration;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const totalTimeMinutes = (totalWorkSessions * workDuration) + totalBreakTime;
|
||||
|
||||
return {
|
||||
current: currentCycle,
|
||||
total: totalCycles,
|
||||
workSessionsRemaining: workSessionsRemaining,
|
||||
totalWorkSessions: totalWorkSessions,
|
||||
totalTimeMinutes: totalTimeMinutes
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset estimation state (call when user wants to clear estimation)
|
||||
*/
|
||||
public resetEstimation(): void {
|
||||
this.state.pomodoroIsEstimationActive = false;
|
||||
this.state.pomodoroEstimatedTotalCycles = null;
|
||||
this.state.pomodoroEstimatedWorkSessions = null;
|
||||
this.state.pomodoroUserHasModifiedSettings = false;
|
||||
this.plugin.savePluginData();
|
||||
this.notifyUpdate();
|
||||
}
|
||||
|
||||
|
||||
// --- Internal Logic ---
|
||||
|
||||
|
|
|
|||
97
styles.css
97
styles.css
|
|
@ -2802,6 +2802,16 @@ button.disabled:hover {
|
|||
.pomodoro-visibility-toggle-container {
|
||||
display: none !important;
|
||||
}
|
||||
.sidebar-pomodoro-section {
|
||||
width: 100%;
|
||||
margin-top: 8px;
|
||||
margin-bottom: 8px;
|
||||
padding: 8px;
|
||||
background-color: var(--background-secondary);
|
||||
border-radius: var(--radius-m);
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.sidebar-pomodoro-section-container {
|
||||
width: 100%;
|
||||
margin-top: 8px;
|
||||
|
|
@ -2983,14 +2993,99 @@ button.disabled:hover {
|
|||
.pomodoro-calculation-result {
|
||||
font-size: 0.9em;
|
||||
margin-top: 8px;
|
||||
padding: 8px;
|
||||
padding: 10px;
|
||||
background-color: var(--background-secondary-alt);
|
||||
border-radius: var(--radius-s);
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
line-height: 1.4;
|
||||
}
|
||||
.pomodoro-calculation-result p {
|
||||
margin: 4px 0;
|
||||
}
|
||||
.pomodoro-cycle-progress {
|
||||
font-size: 0.75em;
|
||||
color: var(--text-muted);
|
||||
text-align: center;
|
||||
margin-top: 4px;
|
||||
padding: 2px 6px;
|
||||
border-radius: var(--radius-s);
|
||||
transition: var(--sf-transition);
|
||||
line-height: 1.2;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.pomodoro-cycle-progress.cycle-active {
|
||||
color: var(--sf-info);
|
||||
background-color: var(--background-modifier-hover);
|
||||
font-weight: 500;
|
||||
}
|
||||
.pomodoro-override-container {
|
||||
margin: 12px 0;
|
||||
padding: 10px;
|
||||
background-color: var(--background-secondary-alt);
|
||||
border-radius: var(--radius-s);
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.pomodoro-override-label {
|
||||
font-size: 0.9em;
|
||||
color: var(--text-normal);
|
||||
font-weight: 500;
|
||||
margin-bottom: 6px;
|
||||
display: block;
|
||||
}
|
||||
.pomodoro-override-inputs {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.pomodoro-override-hours,
|
||||
.pomodoro-override-minutes {
|
||||
width: 50px;
|
||||
background-color: var(--background-primary);
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
border-radius: var(--radius-s);
|
||||
padding: 4px 6px;
|
||||
text-align: center;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
.pomodoro-override-hours:focus,
|
||||
.pomodoro-override-minutes:focus {
|
||||
outline: none;
|
||||
border-color: var(--interactive-accent);
|
||||
box-shadow: 0 0 0 2px rgba(var(--interactive-accent-rgb), 0.2);
|
||||
}
|
||||
.pomodoro-override-label-small {
|
||||
font-size: 0.8em;
|
||||
color: var(--text-muted);
|
||||
font-weight: 400;
|
||||
}
|
||||
.pomodoro-override-toggle-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.pomodoro-add-to-estimation {
|
||||
margin: 0;
|
||||
}
|
||||
.pomodoro-toggle-label {
|
||||
font-size: 0.85em;
|
||||
color: var(--text-normal);
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
.pomodoro-override-info {
|
||||
color: var(--sf-info);
|
||||
font-style: italic;
|
||||
font-size: 0.9em;
|
||||
margin-top: 4px;
|
||||
padding: 4px 6px;
|
||||
background-color: var(--background-primary);
|
||||
border-radius: var(--radius-s);
|
||||
border-left: 3px solid var(--sf-info);
|
||||
}
|
||||
|
||||
/* styles/responsive.css */
|
||||
@media (max-width: 768px) {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,17 @@
|
|||
display: none !important; /* Hide the old toggle button */
|
||||
}
|
||||
|
||||
.sidebar-pomodoro-section {
|
||||
width: 100%; /* Make it fit the width of its parent in the sidebar */
|
||||
margin-top: 8px; /* Space above Pomodoro section */
|
||||
margin-bottom: 8px; /* Space below Pomodoro section */
|
||||
padding: 8px; /* Padding inside the Pomodoro container */
|
||||
background-color: var(--background-secondary); /* Match sidebar section bg */
|
||||
border-radius: var(--radius-m); /* Consistent border radius */
|
||||
border: 1px solid var(--background-modifier-border); /* Consistent border */
|
||||
box-sizing: border-box; /* Ensure padding and border are within width */
|
||||
}
|
||||
|
||||
.sidebar-pomodoro-section-container {
|
||||
width: 100%; /* Make it fit the width of its parent in the sidebar */
|
||||
margin-top: 8px; /* Space above Pomodoro section */
|
||||
|
|
@ -207,11 +218,110 @@
|
|||
.pomodoro-calculation-result {
|
||||
font-size: 0.9em;
|
||||
margin-top: 8px; /* Increased margin */
|
||||
padding: 8px; /* Increased padding */
|
||||
padding: 10px; /* Increased padding */
|
||||
background-color: var(--background-secondary-alt);
|
||||
border-radius: var(--radius-s);
|
||||
border: 1px solid var(--background-modifier-border); /* Add border for definition */
|
||||
line-height: 1.4;
|
||||
}
|
||||
.pomodoro-calculation-result p {
|
||||
margin: 4px 0; /* Spacing for paragraphs within result */
|
||||
}
|
||||
|
||||
/* Cycle Tracking Styles */
|
||||
.pomodoro-cycle-progress {
|
||||
font-size: 0.75em;
|
||||
color: var(--text-muted);
|
||||
text-align: center;
|
||||
margin-top: 4px;
|
||||
padding: 2px 6px;
|
||||
border-radius: var(--radius-s);
|
||||
transition: var(--sf-transition);
|
||||
line-height: 1.2;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.pomodoro-cycle-progress.cycle-active {
|
||||
color: var(--sf-info);
|
||||
background-color: var(--background-modifier-hover);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* User Override Styles */
|
||||
.pomodoro-override-container {
|
||||
margin: 12px 0;
|
||||
padding: 10px;
|
||||
background-color: var(--background-secondary-alt);
|
||||
border-radius: var(--radius-s);
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.pomodoro-override-label {
|
||||
font-size: 0.9em;
|
||||
color: var(--text-normal);
|
||||
font-weight: 500;
|
||||
margin-bottom: 6px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.pomodoro-override-inputs {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.pomodoro-override-hours,
|
||||
.pomodoro-override-minutes {
|
||||
width: 50px;
|
||||
background-color: var(--background-primary);
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
border-radius: var(--radius-s);
|
||||
padding: 4px 6px;
|
||||
text-align: center;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.pomodoro-override-hours:focus,
|
||||
.pomodoro-override-minutes:focus {
|
||||
outline: none;
|
||||
border-color: var(--interactive-accent);
|
||||
box-shadow: 0 0 0 2px rgba(var(--interactive-accent-rgb), 0.2);
|
||||
}
|
||||
|
||||
.pomodoro-override-label-small {
|
||||
font-size: 0.8em;
|
||||
color: var(--text-muted);
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.pomodoro-override-toggle-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.pomodoro-add-to-estimation {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.pomodoro-toggle-label {
|
||||
font-size: 0.85em;
|
||||
color: var(--text-normal);
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.pomodoro-override-info {
|
||||
color: var(--sf-info);
|
||||
font-style: italic;
|
||||
font-size: 0.9em;
|
||||
margin-top: 4px;
|
||||
padding: 4px 6px;
|
||||
background-color: var(--background-primary);
|
||||
border-radius: var(--radius-s);
|
||||
border-left: 3px solid var(--sf-info);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -99,6 +99,13 @@ export class SpaceforgeSettingTab extends PluginSettingTab {
|
|||
pomodoroSessionsCompletedInCycle: this.plugin.pluginState.pomodoroSessionsCompletedInCycle,
|
||||
pomodoroIsRunning: this.plugin.pluginState.pomodoroIsRunning,
|
||||
pomodoroEndTimeMs: this.plugin.pluginState.pomodoroEndTimeMs ?? null, // Add the missing field
|
||||
pomodoroEstimatedTotalCycles: this.plugin.pluginState.pomodoroEstimatedTotalCycles ?? null,
|
||||
pomodoroEstimatedWorkSessions: this.plugin.pluginState.pomodoroEstimatedWorkSessions ?? null,
|
||||
pomodoroIsEstimationActive: this.plugin.pluginState.pomodoroIsEstimationActive ?? false,
|
||||
pomodoroUserHasModifiedSettings: this.plugin.pluginState.pomodoroUserHasModifiedSettings ?? false,
|
||||
pomodoroUserOverrideHours: this.plugin.pluginState.pomodoroUserOverrideHours ?? 0,
|
||||
pomodoroUserOverrideMinutes: this.plugin.pluginState.pomodoroUserOverrideMinutes ?? 0,
|
||||
pomodoroUserAddToEstimation: this.plugin.pluginState.pomodoroUserAddToEstimation ?? false,
|
||||
};
|
||||
|
||||
const dataToExport: SpaceforgePluginData = {
|
||||
|
|
|
|||
|
|
@ -125,6 +125,33 @@ export class ListViewRenderer {
|
|||
// }
|
||||
|
||||
private async _ensureAndUpdateReviewButtonsSection(container: HTMLElement, notesForDisplay: ReviewSchedule[], selectedNotes: string[]): Promise<void> {
|
||||
// --- Pomodoro Section (Always visible when enabled, independent of notes) ---
|
||||
let pomodoroContainer = container.querySelector(".sidebar-pomodoro-section") as HTMLElement;
|
||||
if (!pomodoroContainer) {
|
||||
pomodoroContainer = container.createDiv("sidebar-pomodoro-section");
|
||||
const pomodoroSectionContainerEl = pomodoroContainer.createDiv("sidebar-pomodoro-button-container");
|
||||
}
|
||||
|
||||
// Update Pomodoro section visibility and content
|
||||
if (this.pomodoroUIManager && pomodoroContainer) {
|
||||
const pomodoroSectionContainerEl = pomodoroContainer.querySelector(".sidebar-pomodoro-button-container") as HTMLElement;
|
||||
if (pomodoroSectionContainerEl) {
|
||||
this.pomodoroUIManager.attachAndRender(pomodoroSectionContainerEl);
|
||||
if (this.plugin.settings.pomodoroEnabled) {
|
||||
pomodoroContainer.style.display = '';
|
||||
this.pomodoroUIManager.showPomodoroSection(true);
|
||||
this.pomodoroUIManager.updatePomodoroUI();
|
||||
|
||||
// Automatically calculate estimation for current notes
|
||||
this.pomodoroUIManager.calculateAndDisplayEstimation();
|
||||
} else {
|
||||
pomodoroContainer.style.display = 'none';
|
||||
this.pomodoroUIManager.showPomodoroSection(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- Review Buttons Section (Only visible when there are notes) ---
|
||||
let reviewButtonsContainer = container.querySelector(".review-buttons-container") as HTMLElement;
|
||||
|
||||
// Visibility of review buttons should depend on whether there are notes in the current context (notesForDisplay)
|
||||
|
|
@ -138,8 +165,6 @@ export class ListViewRenderer {
|
|||
const nextNoteBtn = navButtonsContainer.createEl("button", { text: "Next", title: "Navigate to Next Note", cls: "review-all-button" });
|
||||
nextNoteBtn.addEventListener("click", () => { this.plugin.reviewController.navigateToNextNote(); });
|
||||
|
||||
reviewButtonsContainer.createDiv("sidebar-pomodoro-button-container"); // Placeholder for Pomodoro
|
||||
|
||||
const reviewCurrentBtn = reviewButtonsContainer.createEl("button", { text: "Review Current Note", title: "Review the currently open note if it's due", cls: "review-all-button" });
|
||||
reviewCurrentBtn.addEventListener("click", () => { this.plugin.reviewController.reviewCurrentNote(); });
|
||||
const reviewAllBtn = reviewButtonsContainer.createEl("button", { text: "Review All", title: "Start Reviewing All Due Notes", cls: "review-all-button" });
|
||||
|
|
@ -151,18 +176,6 @@ export class ListViewRenderer {
|
|||
}
|
||||
}
|
||||
reviewButtonsContainer.style.display = '';
|
||||
|
||||
// Pomodoro section
|
||||
const pomodoroSectionContainerEl = reviewButtonsContainer.querySelector(".sidebar-pomodoro-button-container") as HTMLElement;
|
||||
if (this.pomodoroUIManager && pomodoroSectionContainerEl) {
|
||||
this.pomodoroUIManager.attachAndRender(pomodoroSectionContainerEl); // This method will be refactored to be non-destructive
|
||||
if (this.plugin.settings.pomodoroEnabled) {
|
||||
this.pomodoroUIManager.showPomodoroSection(true); // Controls overall visibility
|
||||
this.pomodoroUIManager.updatePomodoroUI(); // Updates internal state and button text
|
||||
} else {
|
||||
this.pomodoroUIManager.showPomodoroSection(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Bulk action buttons
|
||||
let bulkActionButtons = container.querySelector(".review-bulk-actions") as HTMLElement;
|
||||
|
|
|
|||
|
|
@ -21,6 +21,14 @@ export class PomodoroUIManager {
|
|||
private pomodoroQuickLongInput: HTMLInputElement | null = null;
|
||||
private pomodoroQuickSessionsInput: HTMLInputElement | null = null;
|
||||
private pomodoroCalculationResultEl: HTMLElement | null = null;
|
||||
|
||||
// New estimation and cycle tracking elements (moved to calculation panel)
|
||||
private pomodoroCycleProgressEl: HTMLElement | null = null;
|
||||
|
||||
// User override input elements
|
||||
private pomodoroUserOverrideHoursInput: HTMLInputElement | null = null;
|
||||
private pomodoroUserOverrideMinutesInput: HTMLInputElement | null = null;
|
||||
private pomodoroUserAddToEstimationCheckbox: HTMLInputElement | null = null;
|
||||
|
||||
// private isPomodoroSectionOpen: boolean = false; // No longer needed, section is always "open"
|
||||
private areButtonsVisible: boolean = true; // For Play/Pause/Skip buttons
|
||||
|
|
@ -237,6 +245,12 @@ export class PomodoroUIManager {
|
|||
this.pomodoroSkipBtn.addEventListener("click", () => this.plugin.pomodoroService.skipSession());
|
||||
}
|
||||
|
||||
// Cycle Progress Display (shows current cycle and remaining sessions)
|
||||
if (!this.pomodoroCycleProgressEl || this.pomodoroCycleProgressEl.parentElement !== container) {
|
||||
this.pomodoroCycleProgressEl?.remove();
|
||||
this.pomodoroCycleProgressEl = container.createDiv("pomodoro-cycle-progress");
|
||||
}
|
||||
|
||||
// Quick Settings Toggle Button - REMOVED
|
||||
// if (!this.pomodoroQuickSettingsToggleBtn || this.pomodoroQuickSettingsToggleBtn.parentElement !== mainControlsRow) {
|
||||
// this.pomodoroQuickSettingsToggleBtn?.remove();
|
||||
|
|
@ -302,6 +316,35 @@ export class PomodoroUIManager {
|
|||
// }
|
||||
// });
|
||||
|
||||
// User override time inputs
|
||||
const overrideContainer = this.pomodoroQuickSettingsPanelEl.createDiv("pomodoro-override-container");
|
||||
const overrideLabel = overrideContainer.createEl("label", { text: "Override time (optional):", cls: "pomodoro-override-label" });
|
||||
|
||||
const overrideInputsContainer = overrideContainer.createDiv("pomodoro-override-inputs");
|
||||
this.pomodoroUserOverrideHoursInput = overrideInputsContainer.createEl("input", { type: "number", cls: "pomodoro-override-hours" });
|
||||
this.pomodoroUserOverrideHoursInput.setAttr("min", "0");
|
||||
this.pomodoroUserOverrideHoursInput.setAttr("placeholder", "H");
|
||||
this.pomodoroUserOverrideHoursInput.value = String(this.plugin.pluginState.pomodoroUserOverrideHours);
|
||||
|
||||
const hoursLabel = overrideInputsContainer.createSpan("pomodoro-override-label-small");
|
||||
hoursLabel.setText("h");
|
||||
|
||||
this.pomodoroUserOverrideMinutesInput = overrideInputsContainer.createEl("input", { type: "number", cls: "pomodoro-override-minutes" });
|
||||
this.pomodoroUserOverrideMinutesInput.setAttr("min", "0");
|
||||
this.pomodoroUserOverrideMinutesInput.setAttr("placeholder", "M");
|
||||
this.pomodoroUserOverrideMinutesInput.value = String(this.plugin.pluginState.pomodoroUserOverrideMinutes);
|
||||
|
||||
const minutesLabel = overrideInputsContainer.createSpan("pomodoro-override-label-small");
|
||||
minutesLabel.setText("m");
|
||||
|
||||
// Add to estimation toggle
|
||||
const toggleContainer = overrideContainer.createDiv("pomodoro-override-toggle-container");
|
||||
this.pomodoroUserAddToEstimationCheckbox = toggleContainer.createEl("input", { type: "checkbox", cls: "pomodoro-add-to-estimation" });
|
||||
this.pomodoroUserAddToEstimationCheckbox.checked = this.plugin.pluginState.pomodoroUserAddToEstimation;
|
||||
|
||||
const toggleLabel = toggleContainer.createEl("label", { text: "Add to estimated time", cls: "pomodoro-toggle-label" });
|
||||
toggleLabel.setAttribute("for", "pomodoro-add-to-estimation");
|
||||
|
||||
const calculateBtn = buttonsContainer.createEl("button", { text: "Calculate Reading Time", cls: "pomodoro-quick-calculate-btn" });
|
||||
calculateBtn.addEventListener("click", async () => {
|
||||
const settingsSaved = this._savePomodoroSettings();
|
||||
|
|
@ -323,10 +366,18 @@ export class PomodoroUIManager {
|
|||
private async calculateAndDisplayPomodoroEstimate(): Promise<void> {
|
||||
if (!this.plugin || !this.pomodoroCalculationResultEl) return;
|
||||
|
||||
// Save user override settings
|
||||
this.saveUserOverrideSettings();
|
||||
|
||||
// Use notes from the review controller, which are context-aware (selected date or actual today)
|
||||
const notesForEstimate = this.plugin.reviewController.getTodayNotes();
|
||||
|
||||
if (notesForEstimate.length === 0) {
|
||||
// Check if we have either notes or user override
|
||||
const userOverrideHours = this.plugin.pluginState.pomodoroUserOverrideHours || 0;
|
||||
const userOverrideMinutes = this.plugin.pluginState.pomodoroUserOverrideMinutes || 0;
|
||||
const userOverrideTimeInMinutes = (userOverrideHours * 60) + userOverrideMinutes;
|
||||
|
||||
if (notesForEstimate.length === 0 && userOverrideTimeInMinutes === 0) {
|
||||
const activeDate = this.plugin.reviewController.getCurrentReviewDateOverride();
|
||||
const message = activeDate
|
||||
? `No notes scheduled for ${new Date(activeDate).toLocaleDateString()} to calculate.`
|
||||
|
|
@ -336,54 +387,68 @@ export class PomodoroUIManager {
|
|||
return;
|
||||
}
|
||||
|
||||
let totalReadingTimeInSeconds = 0;
|
||||
for (const note of notesForEstimate) {
|
||||
totalReadingTimeInSeconds += await this.plugin.reviewScheduleService.estimateReviewTime(note.path);
|
||||
}
|
||||
const totalReadingTimeInMinutes = totalReadingTimeInSeconds / 60;
|
||||
|
||||
const settings = this.plugin.settings;
|
||||
const workDuration = settings.pomodoroWorkDuration;
|
||||
const shortBreakDuration = settings.pomodoroShortBreakDuration;
|
||||
const longBreakDuration = settings.pomodoroLongBreakDuration;
|
||||
const sessionsUntilLongBreak = settings.pomodoroSessionsUntilLongBreak;
|
||||
|
||||
let pomodorosNeeded = 0;
|
||||
let sessionsCompletedInCycle = 0;
|
||||
let remainingReadingTimeMinutes = totalReadingTimeInMinutes;
|
||||
let totalBreakTimeInMinutes = 0;
|
||||
|
||||
if (totalReadingTimeInMinutes === 0) {
|
||||
this.pomodoroCalculationResultEl.setText("Estimated reading time is 0 minutes.");
|
||||
this.pomodoroCalculationResultEl.style.display = 'block';
|
||||
return;
|
||||
// Use the PomodoroService to calculate estimation (this also resets and updates cycle tracking)
|
||||
const result = await this.plugin.pomodoroService.calculateEstimationFromNotes(notesForEstimate);
|
||||
|
||||
if (!result) {
|
||||
this.pomodoroCalculationResultEl.setText("Unable to calculate estimation.");
|
||||
this.pomodoroCalculationResultEl.style.display = 'block';
|
||||
return;
|
||||
}
|
||||
|
||||
while (remainingReadingTimeMinutes > 0) {
|
||||
pomodorosNeeded++;
|
||||
remainingReadingTimeMinutes -= workDuration;
|
||||
sessionsCompletedInCycle++;
|
||||
const { totalReadingTimeInSeconds, totalReadingTimeInMinutes, pomodorosNeeded, totalTimeWithBreaksMinutes } = result;
|
||||
|
||||
if (remainingReadingTimeMinutes <= 0) break;
|
||||
|
||||
if (sessionsCompletedInCycle >= sessionsUntilLongBreak) {
|
||||
totalBreakTimeInMinutes += longBreakDuration;
|
||||
sessionsCompletedInCycle = 0;
|
||||
} else {
|
||||
totalBreakTimeInMinutes += shortBreakDuration;
|
||||
}
|
||||
}
|
||||
|
||||
const totalTimeWithBreaksMinutes = (pomodorosNeeded * workDuration) + totalBreakTimeInMinutes;
|
||||
// Get user override values for display (already declared above)
|
||||
const addToEstimation = this.plugin.pluginState.pomodoroUserAddToEstimation || false;
|
||||
|
||||
const formattedTotalReadingTime = EstimationUtils.formatTime(totalReadingTimeInSeconds);
|
||||
const formattedTotalTimeWithBreaks = EstimationUtils.formatTime(Math.ceil(totalTimeWithBreaksMinutes * 60));
|
||||
|
||||
this.pomodoroCalculationResultEl.empty();
|
||||
this.pomodoroCalculationResultEl.createEl("p", { text: `Estimated reading time for ${notesForEstimate.length} note(s) in current view: ${formattedTotalReadingTime}.` });
|
||||
|
||||
// Show base reading time if we have notes and it wasn't completely overridden
|
||||
if (notesForEstimate.length > 0 && totalReadingTimeInSeconds > 0 && (!userOverrideTimeInMinutes || addToEstimation)) {
|
||||
// Calculate base reading time without overrides for display
|
||||
let baseReadingTimeInSeconds = 0;
|
||||
for (const note of notesForEstimate) {
|
||||
baseReadingTimeInSeconds += await this.plugin.reviewScheduleService.estimateReviewTime(note.path);
|
||||
}
|
||||
const formattedBaseReadingTime = EstimationUtils.formatTime(baseReadingTimeInSeconds);
|
||||
this.pomodoroCalculationResultEl.createEl("p", { text: `Base reading time for ${notesForEstimate.length} note(s): ${formattedBaseReadingTime}.` });
|
||||
} else if (notesForEstimate.length === 0 && userOverrideTimeInMinutes > 0) {
|
||||
// Show message when using only override time
|
||||
this.pomodoroCalculationResultEl.createEl("p", { text: `Using override time only (no notes).` });
|
||||
}
|
||||
|
||||
// Show user override information if applicable
|
||||
if (userOverrideTimeInMinutes > 0) {
|
||||
const overrideText = addToEstimation
|
||||
? `Added ${userOverrideHours}h ${userOverrideMinutes}m override time.`
|
||||
: `Using ${userOverrideHours}h ${userOverrideMinutes}m override time (replacing estimate).`;
|
||||
this.pomodoroCalculationResultEl.createEl("p", { text: overrideText, cls: "pomodoro-override-info" });
|
||||
}
|
||||
|
||||
this.pomodoroCalculationResultEl.createEl("p", { text: `Requires ~${pomodorosNeeded} Pomodoro work session(s).` });
|
||||
this.pomodoroCalculationResultEl.createEl("p", { text: `Total time with breaks: ~${formattedTotalTimeWithBreaks}.` });
|
||||
this.pomodoroCalculationResultEl.style.display = 'block';
|
||||
|
||||
// Update the cycle progress display to show the new estimation
|
||||
this.updateCycleProgressDisplay();
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves user override settings to plugin state
|
||||
*/
|
||||
private saveUserOverrideSettings(): void {
|
||||
const hours = parseInt(this.pomodoroUserOverrideHoursInput?.value || "0");
|
||||
const minutes = parseInt(this.pomodoroUserOverrideMinutesInput?.value || "0");
|
||||
const addToEstimation = this.pomodoroUserAddToEstimationCheckbox?.checked || false;
|
||||
|
||||
this.plugin.pluginState.pomodoroUserOverrideHours = hours;
|
||||
this.plugin.pluginState.pomodoroUserOverrideMinutes = minutes;
|
||||
this.plugin.pluginState.pomodoroUserAddToEstimation = addToEstimation;
|
||||
|
||||
this.plugin.savePluginData();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -487,5 +552,59 @@ export class PomodoroUIManager {
|
|||
if (this.pomodoroCalculationResultEl && this.pomodoroQuickSettingsPanelEl?.style.display === 'none') {
|
||||
this.pomodoroCalculationResultEl.style.display = 'none';
|
||||
}
|
||||
|
||||
// Update cycle progress display
|
||||
this.updateCycleProgressDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Updates the cycle progress display based on current state
|
||||
*/
|
||||
private updateCycleProgressDisplay(): void {
|
||||
if (!this.pomodoroCycleProgressEl) return;
|
||||
|
||||
const cycleProgress = this.plugin.pomodoroService.getCycleProgress();
|
||||
|
||||
if (cycleProgress) {
|
||||
const { current, total, workSessionsRemaining, totalWorkSessions, totalTimeMinutes } = cycleProgress;
|
||||
|
||||
// Calculate completed sessions
|
||||
const completedSessions = totalWorkSessions - workSessionsRemaining;
|
||||
|
||||
// Format total time
|
||||
const totalHours = Math.floor(totalTimeMinutes / 60);
|
||||
const totalMinutes = Math.round(totalTimeMinutes % 60);
|
||||
const timeString = totalHours > 0 ? `${totalHours}H/${totalMinutes}M` : `${totalMinutes}M`;
|
||||
|
||||
this.pomodoroCycleProgressEl.setText(`Cycles ${current}/${total} - Sessions ${completedSessions}/${totalWorkSessions} - ${timeString}`);
|
||||
this.pomodoroCycleProgressEl.style.display = '';
|
||||
this.pomodoroCycleProgressEl.addClass('cycle-active');
|
||||
} else {
|
||||
this.pomodoroCycleProgressEl.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format time in seconds to a readable string
|
||||
*/
|
||||
private formatTime(totalSeconds: number): string {
|
||||
const hours = Math.floor(totalSeconds / 3600);
|
||||
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
||||
|
||||
if (hours > 0) {
|
||||
return `${hours}h ${minutes}m`;
|
||||
} else {
|
||||
return `${minutes}m`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate and display estimation for current notes
|
||||
*/
|
||||
public async calculateAndDisplayEstimation(): Promise<void> {
|
||||
const notesForEstimate = this.plugin.reviewController.getTodayNotes();
|
||||
await this.plugin.pomodoroService.calculateEstimationFromNotes(notesForEstimate);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue