Skip to content

Commit

Permalink
✨ feat: Add a waiting prompt
Browse files Browse the repository at this point in the history
  • Loading branch information
xiangechen committed Jan 31, 2024
1 parent 231d393 commit 6738c5f
Show file tree
Hide file tree
Showing 13 changed files with 189 additions and 56 deletions.
3 changes: 2 additions & 1 deletion packages/chili-core/src/base/pubsub.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ export interface PubSubEventMap {
clearSelectionControl: () => void;
openCommandContext: (command: ICommand) => void;
closeCommandContext: () => void;
showHome: () => void;
displayHome: (show: boolean) => void;
showToast: (message: I18nKeys, ...args: any[]) => void;
showPermanent: (action: () => Promise<void>, message: I18nKeys, ...args: any[]) => void;
showDialog: (title: I18nKeys, context: IPropertyChanged, callback: () => void) => void;
}

Expand Down
1 change: 1 addition & 0 deletions packages/chili-core/src/i18n/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ export default {
"toast.downloading": "Downloading",
"toast.success": "Success",
"toast.fail": "Fail",
"toast.excuting{0}": "Excuting {0}",
"prompt.default":
"Middle mouse button to pan the view, Shift + Middle button to rotate the view, Middle button to scroll the zoom view",
"prompt.select.models": "Please select models",
Expand Down
1 change: 1 addition & 0 deletions packages/chili-core/src/i18n/local.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ export type I18nKeys =
| "toast.downloading"
| "toast.success"
| "toast.fail"
| "toast.excuting{0}"
| "prompt.default"
| "prompt.select.models"
| "prompt.select.edges"
Expand Down
1 change: 1 addition & 0 deletions packages/chili-core/src/i18n/zh-cn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ export default {
"toast.downloading": "正在下载",
"toast.success": "成功",
"toast.fail": "失败",
"toast.excuting{0}": "正在执行{0}",
"prompt.default": "鼠标中键平移视图,Shift + 中键旋转视图,中键滚动缩放视图",
"prompt.polygon.close": "闭合",
"prompt.select.models": "请选择模型",
Expand Down
17 changes: 14 additions & 3 deletions packages/chili-ui/src/home/home.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,20 @@ export const Home = async (app: IApplication) => {
div(
{
className: style.document,
onclick: async () => {
let document = await app.openDocument(item.id);
document?.visual.viewer.activeView?.cameraController.fitContent();
onclick: () => {
if (item.id === app.activeDocument?.id) {
PubSub.default.pub("displayHome", false);
} else {
PubSub.default.pub(
"showPermanent",
async () => {
let document = await app.openDocument(item.id);
document?.visual.viewer.activeView?.cameraController.fitContent();
},
"toast.excuting{0}",
I18n.translate("command.document.open"),
);
}
},
},
img({ className: style.img, src: item.image }),
Expand Down
4 changes: 3 additions & 1 deletion packages/chili-ui/src/mainWindow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Dialog } from "./dialog";
import { Editor } from "./editor";
import { Home } from "./home";
import { Toast } from "./toast";
import { Permanent } from "./permanent";

document.oncontextmenu = (e) => e.preventDefault();

Expand All @@ -26,8 +27,9 @@ export class MainWindow {
const displayHome = debounce(this.displayHome, 100);
PubSub.default.sub("showToast", Toast.show);
PubSub.default.sub("showDialog", Dialog.show);
PubSub.default.sub("showPermanent", Permanent.show);
PubSub.default.sub("activeDocumentChanged", (doc) => displayHome(app, doc === undefined));
PubSub.default.sub("showHome", () => displayHome(app, true));
PubSub.default.sub("displayHome", (show) => displayHome(app, show));
}

private displayHome = (app: IApplication, displayHome: boolean) => {
Expand Down
46 changes: 46 additions & 0 deletions packages/chili-ui/src/permanent.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
dialog {
border: none;
box-shadow: 0px 1px 2px #999;
border-radius: 16px;
padding: 0px;
}

dialog::backdrop {
background-color: rgba(0, 0, 0, 0.5);
}

.loading {
position: relative;
width: 48px;
height: 48px;
border: 2px solid #000;
border-top-color: rgba(0, 0, 0, 0.2);
border-right-color: rgba(0, 0, 0, 0.2);
border-bottom-color: rgba(0, 0, 0, 0.2);
border-radius: 100%;

animation: circle infinite 0.75s linear;
}

@keyframes circle {
0% {
transform: rotate(0);
}

100% {
transform: rotate(360deg);
}
}

.container {
width: fit-content;
height: fit-content;
padding: 24px;
display: flex;
flex-direction: column;
align-items: center;
}

.message {
margin-top: 12px;
}
25 changes: 25 additions & 0 deletions packages/chili-ui/src/permanent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright 2022-2023 the Chili authors. All rights reserved. AGPL-3.0 license.

import { I18n, I18nKeys } from "chili-core";
import { div, span } from "./controls";
import style from "./permanent.module.css";

export class Permanent {
static show(action: () => Promise<void>, message: I18nKeys, ...args: any[]) {
let dialog = document.createElement("dialog");
dialog.appendChild(
div(
{ className: style.container },
div({ className: style.loading }),
span({
className: style.message,
textContent: I18n.translate(message, ...args),
}),
),
);
document.body.appendChild(dialog);
action().finally(() => dialog.remove());

dialog.showModal();
}
}
2 changes: 1 addition & 1 deletion packages/chili-ui/src/ribbon/ribbon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ export class Ribbon extends BindableElement {
label({
textContent: localize("ribbon.tab.file"),
className: style.startup,
onclick: () => PubSub.default.pub("showHome"),
onclick: () => PubSub.default.pub("displayHome", true),
}),
items({
sources: dataContent.ribbonTabs,
Expand Down
31 changes: 24 additions & 7 deletions packages/chili/src/commands/application/openDocument.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
// Copyright 2022-2023 the Chili authors. All rights reserved. AGPL-3.0 license.

import { IApplication, ICommand, IView, PubSub, Serialized, command, readFileAsync } from "chili-core";
import {
AsyncController,
I18n,
IApplication,
ICommand,
IView,
PubSub,
Serialized,
command,
readFileAsync,
} from "chili-core";

@command({
name: "doc.open",
Expand All @@ -9,11 +19,18 @@ import { IApplication, ICommand, IView, PubSub, Serialized, command, readFileAsy
})
export class OpenDocument implements ICommand {
async execute(app: IApplication): Promise<void> {
let files = await readFileAsync(".cd", false);
if (files.status === "success") {
let json: Serialized = JSON.parse(files.value[0].data);
let document = await app.loadDocument(json);
document.visual.viewer.activeView?.cameraController.fitContent();
}
PubSub.default.pub(
"showPermanent",
async () => {
let files = await readFileAsync(".cd", false);
if (files.status === "success") {
let json: Serialized = JSON.parse(files.value[0].data);
let document = await app.loadDocument(json);
document.visual.viewer.activeView?.cameraController.fitContent();
}
},
"toast.excuting{0}",
I18n.translate("command.document.open"),
);
}
}
18 changes: 11 additions & 7 deletions packages/chili/src/commands/application/saveDocument.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright 2022-2023 the Chili authors. All rights reserved. AGPL-3.0 license.

import { command, IApplication, ICommand, PubSub } from "chili-core";
import { AsyncController, command, I18n, IApplication, ICommand, PubSub } from "chili-core";

@command({
name: "doc.save",
Expand All @@ -9,11 +9,15 @@ import { command, IApplication, ICommand, PubSub } from "chili-core";
})
export class SaveDocument implements ICommand {
async execute(app: IApplication): Promise<void> {
if (app.activeDocument) {
await app.activeDocument.save();
PubSub.default.pub("showToast", "toast.document.saved");
} else {
PubSub.default.pub("showToast", "toast.document.noActived");
}
if (!app.activeDocument) return;
PubSub.default.pub(
"showPermanent",
async () => {
await app.activeDocument!.save();
PubSub.default.pub("showToast", "toast.document.saved");
},
"toast.excuting{0}",
I18n.translate("command.document.save"),
);
}
}
21 changes: 15 additions & 6 deletions packages/chili/src/commands/application/toFile.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright 2022-2023 the Chili authors. All rights reserved. AGPL-3.0 license.

import { command, download, IApplication, ICommand, PubSub } from "chili-core";
import { AsyncController, command, download, I18n, IApplication, ICommand, PubSub } from "chili-core";

@command({
name: "doc.saveToFile",
Expand All @@ -9,10 +9,19 @@ import { command, download, IApplication, ICommand, PubSub } from "chili-core";
})
export class SaveDocumentToFile implements ICommand {
async execute(app: IApplication): Promise<void> {
if (app.activeDocument) {
let s = app.activeDocument.serialize();
PubSub.default.pub("showToast", "toast.downloading");
download([JSON.stringify(s)], `${app.activeDocument.name}.cd`);
}
if (!app.activeDocument) return;
PubSub.default.pub(
"showPermanent",
async () => {
await new Promise((r, j) => {
setTimeout(r, 100);
});
let s = app.activeDocument!.serialize();
PubSub.default.pub("showToast", "toast.downloading");
download([JSON.stringify(s)], `${app.activeDocument!.name}.cd`);
},
"toast.excuting{0}",
I18n.translate("command.document.saveToFile"),
);
}
}
75 changes: 45 additions & 30 deletions packages/chili/src/commands/importExport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import {
AsyncController,
GeometryModel,
I18n,
IApplication,
ICommand,
IDocument,
Expand All @@ -29,13 +30,19 @@ let count = 1;
})
export class Import implements ICommand {
async execute(application: IApplication): Promise<void> {
let document = application.activeDocument;
if (!document) return;
let shape = await this.readShape(application);
Transaction.excute(document, "import model", () => {
this.addImportedShape(document!, shape);
});
document.visual.viewer.activeView?.cameraController.fitContent();
if (!application.activeDocument) return;
PubSub.default.pub(
"showPermanent",
async () => {
let shape = await this.readShape(application);
Transaction.excute(application.activeDocument!, "import model", () => {
this.addImportedShape(application.activeDocument!, shape);
});
application.activeDocument!.visual.viewer.activeView?.cameraController.fitContent();
},
"toast.excuting{0}",
I18n.translate("command.import"),
);
}

private addImportedShape = (document: IDocument, shape: [string | undefined, Result<IShape[]>]) => {
Expand Down Expand Up @@ -75,36 +82,44 @@ abstract class Export implements ICommand {
async execute(application: IApplication): Promise<void> {
if (!application.activeDocument) return;
let type = this.getType();
let data = await this.convertShapeAsync(application, type);
if (data) {
PubSub.default.pub("showToast", "toast.downloading");
download([data.data], `${data.name}.${type}`);
}
}

abstract getType(): "iges" | "step";

protected async convertShapeAsync(application: IApplication, type: "iges" | "step") {
let models = await this.selectModelsAsync(application);
if (!models || models.length === 0) {
PubSub.default.pub("showToast", "toast.select.noSelected");
return;
}
let shapes = models.map((x) => x.shape()!);
let shapeString =
type === "iges"
? application.shapeFactory.converter.convertToIGES(...shapes)
: application.shapeFactory.converter.convertToSTEP(...shapes);
if (!shapeString.success) {
PubSub.default.pub("showToast", "toast.converter.error");
return;
}
return {
name: `${models[0].name}`,
data: shapeString.value,
};

PubSub.default.pub(
"showPermanent",
async () => {
let shapes = models!.map((x) => x.shape()!);
let shapeString = await this.convertAsync(application, type, ...shapes);
if (!shapeString.success) {
PubSub.default.pub("showToast", "toast.converter.error");
return;
}
PubSub.default.pub("showToast", "toast.downloading");
download([shapeString.value], `${models![0].name}.${type}`);
},
"toast.excuting{0}",
"",
);
}

private async convertAsync(
application: IApplication,
type: string,
...shapes: IShape[]
): Promise<Result<string>> {
await new Promise((r, j) => {
setTimeout(r, 50);
}); // 等待弹窗完成
return type === "iges"
? application.shapeFactory.converter.convertToIGES(...shapes)
: application.shapeFactory.converter.convertToSTEP(...shapes);
}

abstract getType(): "iges" | "step";

private async selectModelsAsync(application: IApplication) {
let models = application
.activeDocument!.selection.getSelectedNodes()
Expand Down

0 comments on commit 6738c5f

Please sign in to comment.