mirror of
https://github.com/taskgenius/taskgenius-plugin.git
synced 2026-07-22 06:40:25 +00:00
Implement just in readMode View.
This commit is contained in:
parent
7919245b6c
commit
5c6b92cd49
3 changed files with 195 additions and 11 deletions
7
.gitignore
vendored
7
.gitignore
vendored
|
|
@ -25,6 +25,10 @@ data.json
|
|||
# Exclude macOS Finder (System Explorer) View States
|
||||
.DS_Store
|
||||
|
||||
styles.css
|
||||
|
||||
package-lock.json
|
||||
|
||||
# cursorrules
|
||||
.cursorrules
|
||||
|
||||
|
|
@ -33,4 +37,5 @@ data.json
|
|||
|
||||
# translations
|
||||
scripts
|
||||
translation-templates
|
||||
translation-templates
|
||||
._data.json
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import { RegExpCursor } from "./regexp-cursor";
|
|||
import TaskProgressBarPlugin, { showPopoverWithProgressBar } from "..";
|
||||
import { shouldHideProgressBarInLivePriview } from "../utils";
|
||||
import "../styles/progressbar.css";
|
||||
import { TaskGoalManager } from "src/utils/goal/main";
|
||||
|
||||
interface Tasks {
|
||||
completed: number;
|
||||
|
|
@ -702,6 +703,10 @@ export function taskProgressBarExtension(
|
|||
line.from,
|
||||
line.to
|
||||
);
|
||||
|
||||
// Extract the task text and check for goal information
|
||||
const customGoal = TaskGoalManager.extractTaskAndGoalInfo(lineText);
|
||||
|
||||
if (
|
||||
!lineText ||
|
||||
!/^[\s|\t]*([-*+]|\d+\.)\s\[(.)\]/.test(lineText)
|
||||
|
|
@ -724,9 +729,10 @@ export function taskProgressBarExtension(
|
|||
if (!rangeText || rangeText.length === 1) continue;
|
||||
|
||||
const tasksNum = this.extractTasksFromRange(
|
||||
range,
|
||||
range,
|
||||
view.state,
|
||||
true
|
||||
true,
|
||||
customGoal // Add custom goal to the task count
|
||||
);
|
||||
|
||||
if (tasksNum.total === 0) continue;
|
||||
|
|
@ -840,14 +846,15 @@ export function taskProgressBarExtension(
|
|||
private extractTasksFromRange(
|
||||
range: TextRange,
|
||||
state: EditorState,
|
||||
isBullet: boolean
|
||||
isBullet: boolean,
|
||||
customGoal?: number | null
|
||||
): Tasks {
|
||||
const textArray = this.getDocumentTextArray(
|
||||
state.doc,
|
||||
range.from,
|
||||
range.to
|
||||
);
|
||||
return this.calculateTasksNum(textArray, isBullet);
|
||||
return this.calculateTasksNum(textArray, isBullet, customGoal);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1275,7 +1282,8 @@ export function taskProgressBarExtension(
|
|||
|
||||
public calculateTasksNum(
|
||||
textArray: string[],
|
||||
bullet: boolean
|
||||
bullet: boolean,
|
||||
customGoal?: number | null
|
||||
): Tasks {
|
||||
if (!textArray || textArray.length === 0) {
|
||||
return {
|
||||
|
|
@ -1315,7 +1323,9 @@ export function taskProgressBarExtension(
|
|||
let planned: number = 0;
|
||||
let total: number = 0;
|
||||
let level: number = 0;
|
||||
|
||||
let completedGoalValue: number = 0;
|
||||
let totalGoalValue: number = 0;
|
||||
|
||||
// Get tab size from vault config
|
||||
const tabSize = this.getTabSize();
|
||||
|
||||
|
|
@ -1324,6 +1334,7 @@ export function taskProgressBarExtension(
|
|||
mark: string;
|
||||
status: string;
|
||||
lineText: string;
|
||||
goalValue?: number;
|
||||
}[] = [];
|
||||
|
||||
// Determine indentation level for bullets
|
||||
|
|
@ -1374,6 +1385,24 @@ export function taskProgressBarExtension(
|
|||
// Get the task status
|
||||
const status = this.getTaskStatus(lineTextTrimmed);
|
||||
|
||||
// Extract task text to check for task-specific goal
|
||||
const taskText = TaskGoalManager.extractTaskText(lineTextTrimmed);
|
||||
let taskGoalValue = 0;
|
||||
|
||||
if (taskText) {
|
||||
// Check for task-specific goal
|
||||
const taskGoal = TaskGoalManager.extractTaskSpecificGoal(taskText);
|
||||
if (taskGoal !== null) {
|
||||
taskGoalValue = taskGoal;
|
||||
totalGoalValue += taskGoalValue;
|
||||
|
||||
// If task is completed, add its goal value to completedGoalValue
|
||||
if (status === "completed") {
|
||||
completedGoalValue += taskGoalValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Extract the mark for debugging
|
||||
const markMatch = lineTextTrimmed.match(/\[(.)]/);
|
||||
if (markMatch && markMatch[1]) {
|
||||
|
|
@ -1381,6 +1410,7 @@ export function taskProgressBarExtension(
|
|||
mark: markMatch[1],
|
||||
status: status,
|
||||
lineText: lineTextTrimmed,
|
||||
goalValue: taskGoalValue > 0 ? taskGoalValue : undefined
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -1450,7 +1480,7 @@ export function taskProgressBarExtension(
|
|||
}
|
||||
}
|
||||
|
||||
// Ensure counts don't exceed total
|
||||
// Ensure counts don't exceed total
|
||||
completed = Math.min(completed, total);
|
||||
inProgress = Math.min(inProgress, total - completed);
|
||||
abandoned = Math.min(abandoned, total - completed - inProgress);
|
||||
|
|
@ -1460,15 +1490,26 @@ export function taskProgressBarExtension(
|
|||
);
|
||||
notStarted =
|
||||
total - completed - inProgress - abandoned - planned;
|
||||
|
||||
return {
|
||||
|
||||
// Use the TaskGoalManager to adjust counts based on goals
|
||||
const taskCounts = {
|
||||
completed,
|
||||
total,
|
||||
inProgress,
|
||||
abandoned,
|
||||
notStarted,
|
||||
planned,
|
||||
planned
|
||||
};
|
||||
|
||||
// Apply goal-based adjustments using the TaskGoalManager
|
||||
const adjustedCounts = TaskGoalManager.adjustTaskCountsForGoals(
|
||||
taskCounts,
|
||||
customGoal ? customGoal : null,
|
||||
completedGoalValue,
|
||||
totalGoalValue
|
||||
);
|
||||
|
||||
return adjustedCounts;
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
|||
138
src/utils/goal/main.ts
Normal file
138
src/utils/goal/main.ts
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
/**
|
||||
* Goal Tracking System
|
||||
*
|
||||
* This module handles goal-related functionality for tasks in Obsidian Task Genius.
|
||||
* It supports extracting goal information from task text using g::number and goal::number formats.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a collection of task-specific goal values
|
||||
*/
|
||||
export interface TaskGoalValues {
|
||||
/** Sum of goal values from completed tasks */
|
||||
completedGoalValue: number;
|
||||
/** Sum of all goal values from tasks */
|
||||
totalGoalValue: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class that manages all goal-related functionality
|
||||
*/
|
||||
export class TaskGoalManager {
|
||||
/**
|
||||
* Extract the text content of a task from a markdown line
|
||||
*
|
||||
* @param lineText The full text of the markdown line containing the task
|
||||
* @return The extracted task text or null if no task was found
|
||||
*/
|
||||
static extractTaskText(lineText: string): string | null {
|
||||
if (!lineText) return null;
|
||||
|
||||
const taskTextMatch = lineText.match(/^[\s|\t]*([-*+]|\d+\.)\s\[(.)\]\s*(.*?)$/);
|
||||
if (taskTextMatch && taskTextMatch[3]) {
|
||||
return taskTextMatch[3].trim();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static isGoalActive(taskText: string): boolean {
|
||||
if (!taskText) return false;
|
||||
|
||||
// Check for the presence of g:: or goal:: in the task text
|
||||
const goalMatch = taskText.match(/\b(g|goal)::(\d+)\b/i);
|
||||
return !!goalMatch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the goal value from a task text
|
||||
* Supports only g::number or goal::number format
|
||||
*
|
||||
* @param taskText The task text to extract the goal from
|
||||
* @return The extracted goal value or null if no goal found
|
||||
*/
|
||||
static extractTaskSpecificGoal(taskText: string): number | null {
|
||||
if (!taskText) return null;
|
||||
|
||||
// Match only the patterns g::number or goal::number
|
||||
const goalMatch = taskText.match(/\b(g|goal)::(\d+)\b/i);
|
||||
if (!goalMatch) return null;
|
||||
|
||||
return Number(goalMatch[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract task text and goal information from a line
|
||||
*
|
||||
* @param lineText The full text of the markdown line containing the task
|
||||
* @return The extracted goal value or null if no goal found
|
||||
*/
|
||||
static extractTaskAndGoalInfo(lineText: string | null): number | null {
|
||||
if (!lineText) return null;
|
||||
|
||||
// Extract task text
|
||||
const taskText = TaskGoalManager.extractTaskText(lineText);
|
||||
if (!taskText) return null;
|
||||
|
||||
// Check for goal in g::number or goal::number format
|
||||
return TaskGoalManager.extractTaskSpecificGoal(taskText);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust task counts based on goal values
|
||||
*
|
||||
* @param taskCounts Current task count values
|
||||
* @param customGoal Custom goal total value
|
||||
* @param completedGoalValue Sum of goal values from completed tasks
|
||||
* @param totalGoalValue Sum of all goal values
|
||||
* @return Updated task counts with goal-based adjustments
|
||||
*/
|
||||
static adjustTaskCountsForGoals(
|
||||
taskCounts: {
|
||||
completed: number;
|
||||
total: number;
|
||||
inProgress?: number;
|
||||
abandoned?: number;
|
||||
notStarted?: number;
|
||||
planned?: number;
|
||||
},
|
||||
customGoal: number | null,
|
||||
completedGoalValue: number,
|
||||
totalGoalValue: number
|
||||
) {
|
||||
const { completed, total, inProgress = 0, abandoned = 0, planned = 0 } = taskCounts;
|
||||
let adjustedCounts = { ...taskCounts };
|
||||
|
||||
// If we have a custom goal specified with g::number format, use it as the total
|
||||
if (customGoal !== null) {
|
||||
// Always set the total to be the custom goal when specified
|
||||
adjustedCounts.total = customGoal;
|
||||
|
||||
// If we also have task-specific goals, use the goal values to calculate completion
|
||||
if (totalGoalValue > 0) {
|
||||
// Calculate the percentage of completion based on goal values
|
||||
const completionRatio = completedGoalValue / customGoal;
|
||||
console.log("Completion ratio:", completionRatio);
|
||||
console.log("Custom goal:", customGoal);
|
||||
|
||||
// Calculate completed count based on the goal completion ratio
|
||||
adjustedCounts.completed = Math.round(completionRatio * customGoal);
|
||||
adjustedCounts.completed = Math.min(adjustedCounts.completed, customGoal); // Ensure it doesn't exceed total
|
||||
|
||||
// Adjust other counts proportionally
|
||||
adjustedCounts.notStarted = customGoal - adjustedCounts.completed - inProgress - abandoned - (planned || 0);
|
||||
adjustedCounts.notStarted = Math.max(0, adjustedCounts.notStarted); // Ensure it's not negative
|
||||
} else {
|
||||
// If no task-specific goals, use the completed tasks against the custom total goal
|
||||
adjustedCounts.completed = Math.min(completed, customGoal);
|
||||
|
||||
// Adjust notStarted to make the math work out with the new total
|
||||
adjustedCounts.notStarted = customGoal - adjustedCounts.completed - inProgress - abandoned - (planned || 0);
|
||||
adjustedCounts.notStarted = Math.max(0, adjustedCounts.notStarted);
|
||||
}
|
||||
}
|
||||
console.log("Adjusted task counts for goals:", adjustedCounts);
|
||||
|
||||
return adjustedCounts;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue