diff --git a/CHANGELOG.md b/CHANGELOG.md
index deff3a3..84cf254 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+## version 2.3.1
+
+- 状态栏增加简单的计时器
+
## version 2.2.4
- 优化说明简介
diff --git a/README.md b/README.md
index 5d9566c..3c17c3e 100644
--- a/README.md
+++ b/README.md
@@ -23,6 +23,7 @@
- 从[zerotrac.github.io](https://zerotrac.github.io/leetcode_problem_rating/data.json)获取数据进行缓存,数据更新时,可以尝试使用 deleteAllCache,重新获取数据
- [新增区块测试用例](#区块测试用例)
- [新增搬砖功能(重复练习?)](#搬砖功能的说明)
+- [状态栏增加简易计时器](#状态栏增加简易计时器)
# 关于本项目
@@ -64,17 +65,22 @@
- 简单的比较这些用例字符串是否相同
+## 状态栏增加简易计时器
+
+- 查看一个题目时会开始计时,提交一个题目通过后会停止计时
+
## 搬砖功能的说明
diff --git a/package.json b/package.json
index 7cc8925..3cd455d 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
"name": "vscode-leetcode-problem-rating",
"displayName": "LeetCode",
"description": "LeetCode 官方插件增强, 代码开源, 增加 LeetCode 题目难度分, 给个star吧, 球球了",
- "version": "2.2.4",
+ "version": "2.3.1",
"author": "ccagml",
"publisher": "ccagml",
"license": "MIT",
@@ -182,6 +182,44 @@
"title": "Sort Problems",
"category": "LeetCode",
"icon": "$(sort-precedence)"
+ },
+ {
+ "command": "mywiki.commentcreateNote",
+ "title": "Create Note",
+ "enablement": "!commentIsEmpty"
+ },
+ {
+ "command": "mywiki.commentreplyNote",
+ "title": "Reply",
+ "enablement": "!commentIsEmpty"
+ },
+ {
+ "command": "mywiki.commenteditNote",
+ "title": "Edit",
+ "icon": {
+ "dark": "resources/edit_inverse.svg",
+ "light": "resources/edit.svg"
+ }
+ },
+ {
+ "command": "mywiki.commentdeleteNoteComment",
+ "title": "Delete",
+ "icon": {
+ "dark": "resources/close_inverse.svg",
+ "light": "resources/close.svg"
+ }
+ },
+ {
+ "command": "mywiki.commentsaveNote",
+ "title": "Save"
+ },
+ {
+ "command": "mywiki.commentcancelsaveNote",
+ "title": "Cancel"
+ },
+ {
+ "command": "mywiki.commentdispose",
+ "title": "Remove All Notes"
}
],
"viewsContainers": {
@@ -206,6 +244,57 @@
]
},
"menus": {
+ "commandPalette": [
+ {
+ "command": "mywiki.commentcreateNote",
+ "when": "false"
+ },
+ {
+ "command": "mywiki.commentreplyNote",
+ "when": "false"
+ },
+ {
+ "command": "mywiki.commentdeleteNoteComment",
+ "when": "false"
+ }
+ ],
+ "comments/commentThread/title": [],
+ "comments/commentThread/context": [
+ {
+ "command": "mywiki.commentcreateNote",
+ "group": "inline",
+ "when": "commentController == comment-sample && commentThreadIsEmpty"
+ },
+ {
+ "command": "mywiki.commentreplyNote",
+ "group": "inline",
+ "when": "commentController == comment-sample && !commentThreadIsEmpty"
+ }
+ ],
+ "comments/comment/title": [
+ {
+ "command": "mywiki.commenteditNote",
+ "group": "group@1",
+ "when": "commentController == comment-sample"
+ },
+ {
+ "command": "mywiki.commentdeleteNoteComment",
+ "group": "group@2",
+ "when": "commentController == comment-sample && comment == canDelete"
+ }
+ ],
+ "comments/comment/context": [
+ {
+ "command": "mywiki.commentcancelsaveNote",
+ "group": "inline@1",
+ "when": "commentController == comment-sample"
+ },
+ {
+ "command": "mywiki.commentsaveNote",
+ "group": "inline@2",
+ "when": "commentController == comment-sample"
+ }
+ ],
"view/title": [
{
"command": "lcpr.toggleLeetCodeCn",
diff --git a/resources/close.svg b/resources/close.svg
new file mode 100644
index 0000000..fde3440
--- /dev/null
+++ b/resources/close.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/close_inverse.svg b/resources/close_inverse.svg
new file mode 100644
index 0000000..d88aa12
--- /dev/null
+++ b/resources/close_inverse.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/edit.svg b/resources/edit.svg
new file mode 100644
index 0000000..ecde924
--- /dev/null
+++ b/resources/edit.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/edit_inverse.svg b/resources/edit_inverse.svg
new file mode 100644
index 0000000..da956cb
--- /dev/null
+++ b/resources/edit_inverse.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/controller/EventController.ts b/src/controller/EventController.ts
index 658cfc1..1089baa 100644
--- a/src/controller/EventController.ts
+++ b/src/controller/EventController.ts
@@ -8,6 +8,7 @@
*/
import { eventService } from "../service/EventService";
+import { statusBarTimeService } from "../service/StatusBarTimeService";
// 事件的控制器
/* The EventController class has a method called addEvent that calls the addEvent method on the
eventService class */
@@ -22,6 +23,10 @@ class EventContorller {
public addEvent() {
eventService.addEvent();
}
+
+ public every_second() {
+ statusBarTimeService.updateSecond();
+ }
}
export const eventController: EventContorller = new EventContorller();
diff --git a/src/controller/TreeViewController.ts b/src/controller/TreeViewController.ts
index 648b4cf..58a3971 100644
--- a/src/controller/TreeViewController.ts
+++ b/src/controller/TreeViewController.ts
@@ -769,6 +769,12 @@ class TreeViewController implements Disposable {
if (descriptionConfig.showInWebview) {
promises.push(this.showDescriptionView(node));
}
+ promises.push(
+ new Promise(async (resolve, _) => {
+ await eventService.emit("showProblemFinish", node);
+ resolve(1);
+ })
+ );
await Promise.all(promises);
} catch (error) {
diff --git a/src/dao/bricksDao.ts b/src/dao/bricksDao.ts
index 4ed8503..edd5c28 100644
--- a/src/dao/bricksDao.ts
+++ b/src/dao/bricksDao.ts
@@ -143,12 +143,14 @@ class BricksDao {
public async addSubmitTimeByQid(qid: string) {
let temp_data = await this.getInfoByQid(qid);
let submit_time = temp_data.submit_time || [];
- submit_time.push(getDayNow());
+ let submit_now = getDayNow();
+ submit_time.push(submit_now);
temp_data.submit_time = submit_time;
if (!temp_data.type) {
temp_data.type = BricksType.TYPE_2;
}
await this.setInfoByQid(qid, temp_data);
+ return submit_now;
}
public async setTypeByQid(qid: string, type) {
let temp_data = await this.getInfoByQid(qid);
diff --git a/src/extension.ts b/src/extension.ts
index 5de553b..2a24103 100644
--- a/src/extension.ts
+++ b/src/extension.ts
@@ -7,7 +7,27 @@
* Copyright (c) 2022 ccagml . All rights reserved.
*/
-import { ExtensionContext, window, commands, Uri } from "vscode";
+import {
+ ExtensionContext,
+ window,
+ commands,
+ Uri,
+ // MarkdownString,
+ // CommentMode,
+ // CommentAuthorInformation,
+ // CommentThread,
+ // Comment,
+ // CommentReply,
+ // CommentThreadCollapsibleState,
+ // CommentReaction,
+ // CommentController,
+ // CommentingRangeProvider,
+ // CommentOptions,
+ // TextDocument,
+ // CancellationToken,
+ // comments,
+ // Range,
+} from "vscode";
import { fileButtonController } from "./controller/FileButtonController";
import { treeViewController } from "./controller/TreeViewController";
import { NodeModel } from "./model/NodeModel";
@@ -27,12 +47,30 @@ import { getLeetCodeEndpoint } from "./utils/ConfigUtils";
import { BricksType, OutPutType } from "./model/Model";
import { bricksDataService } from "./service/BricksDataService";
import { bricksViewController } from "./controller/BricksViewController";
+import { statusBarTimeService } from "./service/StatusBarTimeService";
+// let commentId = 1;
+
+// class NoteComment implements Comment {
+// id: number;
+// label: string | undefined;
+// constructor(
+// public body: string | MarkdownString,
+// public mode: CommentMode,
+// public author: CommentAuthorInformation,
+// public parent?: CommentThread,
+// public contextValue?: string
+// ) {
+// this.id = ++commentId;
+// }
+// }
// 激活插件
/**
* The main function of the extension. It is called when the extension is activated.
* @param {ExtensionContext} context - ExtensionContext
*/
+
+let lcpr_timer;
export async function activate(context: ExtensionContext): Promise {
try {
// 初始化控制器
@@ -51,6 +89,7 @@ export async function activate(context: ExtensionContext): Promise {
solutionService,
executeService,
markdownService,
+ statusBarTimeService,
fileButtonController,
treeViewController,
window.registerFileDecorationProvider(treeItemDecorationService),
@@ -76,6 +115,9 @@ export async function activate(context: ExtensionContext): Promise {
commands.registerCommand("lcpr.addFavorite", (node: NodeModel) => treeViewController.addFavorite(node)),
commands.registerCommand("lcpr.removeFavorite", (node: NodeModel) => treeViewController.removeFavorite(node)),
commands.registerCommand("lcpr.problems.sort", () => treeViewController.switchSortingStrategy()),
+ commands.registerCommand("lcpr.statusBarTime.start", () => statusBarTimeService.start()),
+ commands.registerCommand("lcpr.statusBarTime.stop", () => statusBarTimeService.stop()),
+ commands.registerCommand("lcpr.statusBarTime.reset", () => statusBarTimeService.reset()),
commands.registerCommand("lcpr.setBricksType0", (node: NodeModel) =>
bricksViewController.setBricksType(node, BricksType.TYPE_0)
),
@@ -104,12 +146,128 @@ export async function activate(context: ExtensionContext): Promise {
// 获取登录状态
await loginContorller.getLoginStatus();
await bricksViewController.initialize();
+ // let aaa;
+ // // A `CommentController` is able to provide comments for documents.
+ // const commentController = comments.createCommentController("comment-sample", "Comment API Sample");
+ // commentController.commentingRangeProvider = {
+ // provideCommentingRanges: (document: TextDocument, token: CancellationToken) => {
+ // let lineCount = document.lineCount;
+ // aaa = commentController.createCommentThread(document.uri, new Range(5, 0, 10, 0), []);
+ // aaa.dispose = () => {
+ // let cac = aaa;
+ // console.log("ssss");
+ // };
+ // console.log(aaa);
+ // return undefined;
+ // },
+ // };
+ // let bbb;
+ // commands.registerCommand("lcpr.previewProblem", (a, b, c) => {
+ // bbb = commentController.createCommentThread(a, new Range(5, 0, 10, 0), [
+ // new NoteComment("ssss", CommentMode.Preview, { name: "vscode" }),
+ // // new NoteComment("bbbb", CommentMode.Preview, { name: "vscode" }),
+ // ]);
+ // }),
+ // context.subscriptions.push(commentController);
+
+ // context.subscriptions.push(
+ // commands.registerCommand("mywiki.commentcreateNote", (reply: CommentReply) => {
+ // replyNote(reply);
+ // })
+ // );
+
+ // context.subscriptions.push(
+ // commands.registerCommand("mywiki.commentreplyNote", (reply: CommentReply) => {
+ // replyNote(reply);
+ // })
+ // );
+
+ // context.subscriptions.push(
+ // commands.registerCommand("mywiki.commentdeleteNoteComment", (comment: NoteComment) => {
+ // let thread = comment.parent;
+ // if (!thread) {
+ // return;
+ // }
+
+ // thread.comments = thread.comments.filter((cmt) => (cmt as NoteComment).id !== comment.id);
+
+ // if (thread.comments.length === 0) {
+ // thread.dispose();
+ // }
+ // })
+ // );
+
+ // context.subscriptions.push(
+ // commands.registerCommand("mywiki.commentcancelsaveNote", (comment: NoteComment) => {
+ // if (!comment.parent) {
+ // return;
+ // }
+
+ // comment.parent.comments = comment.parent.comments.map((cmt) => {
+ // if ((cmt as NoteComment).id === comment.id) {
+ // cmt.mode = CommentMode.Preview;
+ // }
+
+ // return cmt;
+ // });
+ // })
+ // );
+
+ // context.subscriptions.push(
+ // commands.registerCommand("mywiki.commentsaveNote", (comment: NoteComment) => {
+ // if (!comment.parent) {
+ // return;
+ // }
+
+ // comment.parent.comments = comment.parent.comments.map((cmt) => {
+ // if ((cmt as NoteComment).id === comment.id) {
+ // cmt.mode = CommentMode.Preview;
+ // }
+
+ // return cmt;
+ // });
+ // })
+ // );
+
+ // context.subscriptions.push(
+ // commands.registerCommand("mywiki.commenteditNote", (comment: NoteComment) => {
+ // if (!comment.parent) {
+ // return;
+ // }
+
+ // comment.parent.comments = comment.parent.comments.map((cmt) => {
+ // if ((cmt as NoteComment).id === comment.id) {
+ // cmt.mode = CommentMode.Editing;
+ // }
+
+ // return cmt;
+ // });
+ // })
+ // );
+
+ // function replyNote(reply: CommentReply) {
+ // let thread = reply.thread;
+ // let newComment = new NoteComment(
+ // reply.text,
+ // CommentMode.Preview,
+ // { name: "vscode" },
+ // thread,
+ // thread.comments.length ? "canDelete" : undefined
+ // );
+ // if (thread.contextValue === "draft") {
+ // newComment.label = "pending";
+ // }
+
+ // thread.comments = [...thread.comments, newComment];
+ // }
} catch (error) {
logOutput.appendLine(error.toString());
promptForOpenOutputChannel(
"Extension initialization failed. Please open output channel for details.",
OutPutType.error
);
+ } finally {
+ lcpr_timer = setInterval(eventController.every_second, 1000);
}
}
@@ -119,4 +277,8 @@ export function deactivate(): void {
let a = 0;
console.log(a);
}
+ if (lcpr_timer != undefined) {
+ clearInterval(lcpr_timer);
+ lcpr_timer = undefined;
+ }
}
diff --git a/src/service/EventService.ts b/src/service/EventService.ts
index 7ced495..0565c03 100644
--- a/src/service/EventService.ts
+++ b/src/service/EventService.ts
@@ -9,11 +9,12 @@
import { EventEmitter } from "events";
-import { UserStatus } from "../model/Model";
+import { IProblem, UserStatus } from "../model/Model";
import { ISubmitEvent } from "../model/Model";
import { statusBarService } from "../service/StatusBarService";
import { treeDataService } from "../service/TreeDataService";
import { bricksDataService } from "./BricksDataService";
+import { statusBarTimeService } from "./StatusBarTimeService";
class EventService extends EventEmitter {
constructor() {
@@ -34,6 +35,7 @@ class EventService extends EventEmitter {
this.on("submit", (e: ISubmitEvent) => {
treeDataService.checkSubmit(e);
bricksDataService.checkSubmit(e);
+ statusBarTimeService.checkSubmit(e);
});
this.on("searchUserContest", (tt) => {
@@ -46,6 +48,10 @@ class EventService extends EventEmitter {
this.on("explorerNodeMapSet", () => {
bricksDataService.refresh();
});
+
+ this.on("showProblemFinish", (node: IProblem) => {
+ statusBarTimeService.showProblemFinish(node);
+ });
}
}
diff --git a/src/service/StatusBarService.ts b/src/service/StatusBarService.ts
index 7d5f321..1d95a0e 100644
--- a/src/service/StatusBarService.ts
+++ b/src/service/StatusBarService.ts
@@ -72,7 +72,7 @@ class StatusBarService implements Disposable {
}
constructor() {
- this.instance = window.createStatusBarItem();
+ this.instance = window.createStatusBarItem(undefined, 999);
this.setStatusBarVisibility();
this.currentUser = undefined;
this.userStatus = UserStatus.SignedOut;
diff --git a/src/service/StatusBarTimeService.ts b/src/service/StatusBarTimeService.ts
new file mode 100644
index 0000000..d9ea7dd
--- /dev/null
+++ b/src/service/StatusBarTimeService.ts
@@ -0,0 +1,143 @@
+/*
+ * Filename: /home/cc/vscode-leetcode-problem-rating/src/service/StatusBarTimeService.ts
+ * Path: /home/cc/vscode-leetcode-problem-rating
+ * Created Date: Saturday, November 26th 2022, 2:14:53 pm
+ * Author: ccagml
+ *
+ * Copyright (c) 2022 ccagml . All rights reserved.
+ */
+
+import { Disposable, StatusBarItem, window } from "vscode";
+import { IProblem, ISubmitEvent, OutPutType } from "../model/Model";
+import { promptForOpenOutputChannel } from "../utils/OutputUtils";
+import { getDayNow } from "../utils/SystemUtils";
+
+// 状态栏工具
+class StatusBarTimeService implements Disposable {
+ private showBar: StatusBarItem;
+ private startBar: StatusBarItem;
+ private stopBar: StatusBarItem;
+ private resetBar: StatusBarItem;
+ private startTime: number;
+ private saveTime: number;
+ private questionNode: IProblem;
+
+ constructor() {
+ this.showBar = window.createStatusBarItem(undefined, 1004);
+ this.showBar.show();
+
+ this.startBar = window.createStatusBarItem(undefined, 1003);
+ this.startBar.name = "start";
+ this.startBar.text = "start";
+ this.startBar.tooltip = "开始计时";
+ this.startBar.show();
+ this.startBar.command = "lcpr.statusBarTime.start";
+
+ this.stopBar = window.createStatusBarItem(undefined, 1002);
+ this.stopBar.name = "stop";
+ this.stopBar.text = "stop";
+ this.stopBar.tooltip = "暂停计时";
+ this.stopBar.show();
+ this.stopBar.command = "lcpr.statusBarTime.stop";
+
+ this.resetBar = window.createStatusBarItem(undefined, 1001);
+ this.resetBar.name = "reset";
+ this.resetBar.text = "reset";
+ this.resetBar.tooltip = "重置计时";
+ this.resetBar.show();
+ this.resetBar.command = "lcpr.statusBarTime.reset";
+
+ this.startTime = 0;
+ this.saveTime = 0;
+ }
+
+ public showProblemFinish(node) {
+ this.questionNode = node;
+ this.reset();
+ this.start();
+ }
+
+ private getDiffStr(diff: number) {
+ if (diff < 1) {
+ return "0:0:0";
+ } else {
+ let second = diff % 60;
+ diff = Math.floor(diff / 60);
+ let minute = diff % 60;
+ diff = Math.floor(diff / 60);
+ let hour = diff;
+ return `${hour}:${minute}:${second}`;
+ }
+ }
+
+ public getCostTimeStr() {
+ if (this.startTime && this.startTime > 0) {
+ let diff = getDayNow() - this.startTime + this.saveTime;
+ return this.getDiffStr(diff);
+ }
+ return;
+ }
+
+ public async checkSubmit(e: ISubmitEvent) {
+ if (e.sub_type == "submit" && e.accepted) {
+ let msg = this.getCostTimeStr();
+ if (msg) {
+ promptForOpenOutputChannel(`${e.fid}耗时${msg}`, OutPutType.info);
+ }
+ this.stop();
+ }
+ }
+
+ public start() {
+ this.startTime = getDayNow();
+ }
+ public stop() {
+ if (this.startTime > 0) {
+ this.saveTime += getDayNow() - this.startTime;
+ this.startTime = 0;
+ }
+ }
+
+ public reset() {
+ this.startTime = 0;
+ this.saveTime = 0;
+ }
+
+ // 更新状态栏的数据
+ public update_instance(): void {
+ if (this.startTime && this.startTime > 0) {
+ let diff = getDayNow() - this.startTime + this.saveTime;
+ let diffstr = this.getDiffStr(diff);
+ let pre = "做题";
+ if (this.questionNode?.id) {
+ pre = `${this.questionNode?.id}题`;
+ }
+ this.showBar.text = `${pre}计时:${diffstr}`;
+ } else if (this.saveTime > 0) {
+ let diff = this.saveTime;
+ let diffstr = this.getDiffStr(diff);
+ let pre = "做题";
+ if (this.questionNode?.id) {
+ pre = `${this.questionNode?.id}题`;
+ }
+ this.showBar.text = `${pre}题计时:${diffstr}`;
+ } else {
+ this.showBar.text = `做题计时:${this.getDiffStr(0)}`;
+ }
+ }
+
+ // 更新数据
+ public updateSecond(): void {
+ this.update_instance();
+ }
+
+ //销毁数据
+ public dispose(): void {
+ this.showBar.dispose();
+ this.startBar.dispose();
+ this.stopBar.dispose();
+ this.resetBar.dispose();
+ }
+}
+
+export const statusBarTimeService: StatusBarTimeService = new StatusBarTimeService();