Skip to content

Commit 5683a70

Browse files
committed
refactor: Extract explorer cache related code
1 parent 1161e81 commit 5683a70

File tree

4 files changed

+202
-164
lines changed

4 files changed

+202
-164
lines changed

src/explorer/LeetCodeNode.ts

+2-5
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import { Command } from "vscode";
55
import { IProblem, ProblemState } from "../shared";
66

77
export class LeetCodeNode {
8-
constructor(private data: IProblem, private parentNodeName: string, private isProblemNode: boolean = true) { }
8+
9+
constructor(private data: IProblem, private isProblemNode: boolean = true) { }
910

1011
public get locked(): boolean {
1112
return this.data.locked;
@@ -46,10 +47,6 @@ export class LeetCodeNode {
4647
return this.isProblemNode;
4748
}
4849

49-
public get parentName(): string {
50-
return this.parentNodeName;
51-
}
52-
5350
public get previewCommand(): Command {
5451
return {
5552
title: "Preview Problem",

src/explorer/LeetCodeTreeDataProvider.ts

+21-159
Original file line numberDiff line numberDiff line change
@@ -5,30 +5,21 @@ import * as _ from "lodash";
55
import * as os from "os";
66
import * as path from "path";
77
import * as vscode from "vscode";
8-
import * as list from "../commands/list";
9-
import { leetCodeChannel } from "../leetCodeChannel";
108
import { leetCodeManager } from "../leetCodeManager";
11-
import { Category, defaultProblem, IProblem, ProblemState } from "../shared";
12-
import { getWorkspaceConfiguration } from "../utils/workspaceUtils";
9+
import { Category, defaultProblem, ProblemState } from "../shared";
10+
import { explorerNodeManager } from "./explorerNodeManager";
1311
import { LeetCodeNode } from "./LeetCodeNode";
1412

1513
export class LeetCodeTreeDataProvider implements vscode.TreeDataProvider<LeetCodeNode> {
1614

17-
private treeData: {
18-
Difficulty: Map<string, IProblem[]>,
19-
Tag: Map<string, IProblem[]>,
20-
Company: Map<string, IProblem[]>,
21-
Favorite: IProblem[],
22-
};
23-
2415
private onDidChangeTreeDataEvent: vscode.EventEmitter<any> = new vscode.EventEmitter<any>();
2516
// tslint:disable-next-line:member-ordering
2617
public readonly onDidChangeTreeData: vscode.Event<any> = this.onDidChangeTreeDataEvent.event;
2718

2819
constructor(private context: vscode.ExtensionContext) { }
2920

3021
public async refresh(): Promise<void> {
31-
await this.getProblemData();
22+
await explorerNodeManager.refreshCache();
3223
this.onDidChangeTreeDataEvent.fire();
3324
}
3425

@@ -49,7 +40,7 @@ export class LeetCodeTreeDataProvider implements vscode.TreeDataProvider<LeetCod
4940
return {
5041
label: element.isProblem ? `[${element.id}] ${element.name}` : element.name,
5142
tooltip: this.getSubCategoryTooltip(element),
52-
id: `${idPrefix}.${element.parentName}.${element.id}`,
43+
id: `${idPrefix}.${element.id}`,
5344
collapsibleState: element.isProblem ? vscode.TreeItemCollapsibleState.None : vscode.TreeItemCollapsibleState.Collapsed,
5445
contextValue: element.isProblem ? "problem" : element.id.toLowerCase(),
5546
iconPath: this.parseIconPathFromProblemState(element),
@@ -63,91 +54,28 @@ export class LeetCodeTreeDataProvider implements vscode.TreeDataProvider<LeetCod
6354
new LeetCodeNode(Object.assign({}, defaultProblem, {
6455
id: "notSignIn",
6556
name: "Sign in to LeetCode",
66-
}), "ROOT", false),
57+
}), false),
6758
];
6859
}
6960
if (!element) { // Root view
70-
return [
71-
new LeetCodeNode(Object.assign({}, defaultProblem, {
72-
id: Category.Difficulty,
73-
name: Category.Difficulty,
74-
}), "ROOT", false),
75-
new LeetCodeNode(Object.assign({}, defaultProblem, {
76-
id: Category.Tag,
77-
name: Category.Tag,
78-
}), "ROOT", false),
79-
new LeetCodeNode(Object.assign({}, defaultProblem, {
80-
id: Category.Company,
81-
name: Category.Company,
82-
}), "ROOT", false),
83-
new LeetCodeNode(Object.assign({}, defaultProblem, {
84-
id: Category.Favorite,
85-
name: Category.Favorite,
86-
}), "ROOT", false),
87-
];
61+
return explorerNodeManager.getRootNodes();
8862
} else {
89-
switch (element.name) { // First-level
63+
switch (element.id) { // First-level
9064
case Category.Favorite:
91-
const nodes: IProblem[] = this.treeData[Category.Favorite];
92-
return nodes.map((p: IProblem) => new LeetCodeNode(p, Category.Favorite));
65+
return explorerNodeManager.getFavoriteNodes();
9366
case Category.Difficulty:
67+
return explorerNodeManager.getAllDifficultyNodes();
9468
case Category.Tag:
69+
return explorerNodeManager.getAllTagNodes();
9570
case Category.Company:
96-
return this.composeSubCategoryNodes(element);
97-
default: // Second and lower levels
98-
return element.isProblem ? [] : this.composeProblemNodes(element);
99-
}
100-
}
101-
}
102-
103-
private async getProblemData(): Promise<void> {
104-
// clear cache
105-
this.treeData = {
106-
Difficulty: new Map<string, IProblem[]>(),
107-
Tag: new Map<string, IProblem[]>(),
108-
Company: new Map<string, IProblem[]>(),
109-
Favorite: [],
110-
};
111-
for (const problem of await list.listProblems()) {
112-
// Add favorite problem, no matter whether it is solved.
113-
if (problem.isFavorite) {
114-
this.treeData[Category.Favorite].push(problem);
115-
}
116-
// Hide solved problem in other category.
117-
if (problem.state === ProblemState.AC && getWorkspaceConfiguration().get<boolean>("hideSolved")) {
118-
continue;
71+
return explorerNodeManager.getAllCompanyNodes();
72+
default:
73+
if (element.isProblem) {
74+
return [];
75+
}
76+
return explorerNodeManager.getChildrenNodesById(element.id);
11977
}
120-
121-
this.addProblemToTreeData(problem);
122-
}
123-
}
124-
125-
private composeProblemNodes(node: LeetCodeNode): LeetCodeNode[] {
126-
const map: Map<string, IProblem[]> | undefined = this.treeData[node.parentName];
127-
if (!map) {
128-
leetCodeChannel.appendLine(`Category: ${node.parentName} is not available.`);
129-
return [];
130-
}
131-
const problems: IProblem[] = map.get(node.name) || [];
132-
const problemNodes: LeetCodeNode[] = [];
133-
for (const problem of problems) {
134-
problemNodes.push(new LeetCodeNode(problem, node.name));
13578
}
136-
return problemNodes;
137-
}
138-
139-
private composeSubCategoryNodes(node: LeetCodeNode): LeetCodeNode[] {
140-
const category: Category = node.name as Category;
141-
if (category === Category.Favorite) {
142-
leetCodeChannel.appendLine("No sub-level for Favorite nodes");
143-
return [];
144-
}
145-
const map: Map<string, IProblem[]> | undefined = this.treeData[category];
146-
if (!map) {
147-
leetCodeChannel.appendLine(`Category: ${category} is not available.`);
148-
return [];
149-
}
150-
return this.getSubCategoryNodes(map, category);
15179
}
15280

15381
private parseIconPathFromProblemState(element: LeetCodeNode): string {
@@ -171,16 +99,16 @@ export class LeetCodeTreeDataProvider implements vscode.TreeDataProvider<LeetCod
17199

172100
private getSubCategoryTooltip(element: LeetCodeNode): string {
173101
// return '' unless it is a sub-category node
174-
if (element.isProblem || !this.treeData[element.parentName]) {
102+
if (element.isProblem || element.id === "ROOT" || element.id in Category) {
175103
return "";
176104
}
177105

178-
const problems: IProblem[] = this.treeData[element.parentName].get(element.id);
106+
const childernNodes: LeetCodeNode[] = explorerNodeManager.getChildrenNodesById(element.id);
179107

180108
let acceptedNum: number = 0;
181109
let failedNum: number = 0;
182-
for (const prob of problems) {
183-
switch (prob.state) {
110+
for (const node of childernNodes) {
111+
switch (node.state) {
184112
case ProblemState.AC:
185113
acceptedNum++;
186114
break;
@@ -195,73 +123,7 @@ export class LeetCodeTreeDataProvider implements vscode.TreeDataProvider<LeetCod
195123
return [
196124
`AC: ${acceptedNum}`,
197125
`Failed: ${failedNum}`,
198-
`Total: ${problems.length}`,
126+
`Total: ${childernNodes.length}`,
199127
].join(os.EOL);
200128
}
201-
202-
private addProblemToTreeData(problem: IProblem): void {
203-
this.putProblemToMap(this.treeData.Difficulty, problem.difficulty, problem);
204-
for (const tag of problem.tags) {
205-
this.putProblemToMap(this.treeData.Tag, _.startCase(tag), problem);
206-
}
207-
for (const company of problem.companies) {
208-
this.putProblemToMap(this.treeData.Company, _.startCase(company), problem);
209-
}
210-
}
211-
212-
private putProblemToMap(map: Map<string, IProblem[]>, key: string, problem: IProblem): void {
213-
const problems: IProblem[] | undefined = map.get(key);
214-
if (problems) {
215-
problems.push(problem);
216-
} else {
217-
map.set(key, [problem]);
218-
}
219-
}
220-
221-
private getSubCategoryNodes(map: Map<string, IProblem[]>, category: Category): LeetCodeNode[] {
222-
const subCategoryNodes: LeetCodeNode[] = Array.from(map.keys()).map((subCategory: string) => {
223-
return new LeetCodeNode(Object.assign({}, defaultProblem, {
224-
id: subCategory,
225-
name: subCategory,
226-
}), category.toString(), false);
227-
});
228-
this.sortSubCategoryNodes(subCategoryNodes, category);
229-
return subCategoryNodes;
230-
}
231-
232-
private sortSubCategoryNodes(subCategoryNodes: LeetCodeNode[], category: Category): void {
233-
switch (category) {
234-
case Category.Difficulty:
235-
subCategoryNodes.sort((a: LeetCodeNode, b: LeetCodeNode): number => {
236-
function getValue(input: LeetCodeNode): number {
237-
switch (input.name.toLowerCase()) {
238-
case "easy":
239-
return 1;
240-
case "medium":
241-
return 2;
242-
case "hard":
243-
return 3;
244-
default:
245-
return Number.MAX_SAFE_INTEGER;
246-
}
247-
}
248-
return getValue(a) - getValue(b);
249-
});
250-
break;
251-
case Category.Tag:
252-
case Category.Company:
253-
subCategoryNodes.sort((a: LeetCodeNode, b: LeetCodeNode): number => {
254-
if (a.name === "Unknown") {
255-
return 1;
256-
} else if (b.name === "Unknown") {
257-
return -1;
258-
} else {
259-
return Number(a.name > b.name) - Number(a.name < b.name);
260-
}
261-
});
262-
break;
263-
default:
264-
break;
265-
}
266-
}
267129
}

0 commit comments

Comments
 (0)