diff --git a/source/Component/CommandBar/CommandBar.tsx b/source/Component/CommandBar/CommandBar.tsx index 23a1bb6..d0550f8 100644 --- a/source/Component/CommandBar/CommandBar.tsx +++ b/source/Component/CommandBar/CommandBar.tsx @@ -1,24 +1,30 @@ import { Component, ReactNode } from "react"; import { DirectionalHint, IconButton } from "@fluentui/react"; -import { useSetting, useSettingWithEvent, IMixinSettingProps } from "@Context/Setting"; +import { useSetting, IMixinSettingProps } from "@Context/Setting"; import { useStatusWithEvent, IMixinStatusProps } from "@Context/Status"; import { BackgroundLevel, Theme } from "@Component/Theme/Theme"; import { LocalizationTooltipHost } from "@Component/Localization/LocalizationTooltipHost"; -import { AllI18nKeys, I18N } from "@Component/Localization/Localization"; +import { AllI18nKeys } from "@Component/Localization/Localization"; import { SettingPopup } from "@Component/SettingPopup/SettingPopup"; import { BehaviorPopup } from "@Component/BehaviorPopup/BehaviorPopup"; import { MouseMod } from "@GLRender/ClassicRenderer"; -import * as download from "downloadjs"; +import { ArchiveSave } from "@Context/Archive"; import "./CommandBar.scss"; const COMMAND_BAR_WIDTH = 45; -function getRenderButton(param: { +interface IRenderButtonParameter { i18NKey: AllI18nKeys; iconName?: string; click?: () => void; active?: boolean; -}): ReactNode { +} + +interface ICommandBarState { + isSaveRunning: boolean; +} + +function getRenderButton(param: IRenderButtonParameter): ReactNode { return } - -@useSettingWithEvent("language") -@useStatusWithEvent() -class SaveCommandView extends Component { - - public render(): ReactNode { - return getRenderButton({ - iconName: "Save", - i18NKey: "Command.Bar.Save.Info", - click: () => { - - let fileName: string = ""; - let isNewFile: boolean = true; - let isSaved: boolean = false; - - if (this.props.status) { - isNewFile = this.props.status.archive.isNewFile; - fileName = this.props.status.archive.fileName ?? ""; - isSaved = this.props.status.archive.isSaved; - } - - const file = this.props.status?.archive.save(this.props.status.model) ?? ""; - fileName = isNewFile ? I18N(this.props, "Header.Bar.New.File.Name") : fileName; - download(file, fileName, "text/json"); - } - }) - } -} - @useSetting @useStatusWithEvent("mouseModChange", "actuatorStartChange") -class CommandBar extends Component { +class CommandBar extends Component { - render(): ReactNode { + public state: Readonly = { + isSaveRunning: false + }; + + public render(): ReactNode { const mouseMod = this.props.status?.mouseMod ?? MouseMod.Drag; @@ -80,7 +61,22 @@ class CommandBar extends Component { >
- + { + this.setState({ isSaveRunning: false }); + }} + /> + + {getRenderButton({ + iconName: "Save", + i18NKey: "Command.Bar.Save.Info", + click: () => { + this.setState({ + isSaveRunning: true + }); + } + })} {getRenderButton({ iconName: this.props.status?.actuator.start() ? "Pause" : "Play", diff --git a/source/Context/Archive.tsx b/source/Context/Archive.tsx new file mode 100644 index 0000000..cef0fe8 --- /dev/null +++ b/source/Context/Archive.tsx @@ -0,0 +1,91 @@ +import { FunctionComponent, useEffect } from "react"; +import * as download from "downloadjs"; +import { useSetting, IMixinSettingProps, Platform } from "@Context/Setting"; +import { useStatus, IMixinStatusProps } from "@Context/Status"; +import { I18N } from "@Component/Localization/Localization"; + +interface IFileInfo { + fileName: string; + isNewFile: boolean; + isSaved: boolean; + fileUrl?: string; + fileData: () => Promise; +} + +interface IRunnerProps { + running?: boolean; + afterRunning?: () => any; +} + +interface ICallBackProps { + then: () => any; +} + +const ArchiveSaveDownloadView: FunctionComponent = function ArchiveSave(props) { + + const runner = async () => { + const file = await props.fileData(); + setTimeout(() => { + download(file, props.fileName, "text/json"); + props.then(); + }, 100); + } + + useEffect(() => { runner() }, []); + + return <>; +} + +const ArchiveSaveDownload = ArchiveSaveDownloadView; + +/** + * 保存存档文件 + */ +const ArchiveSaveView: FunctionComponent = function ArchiveSave(props) { + + if (!props.running) { + return <>; + } + + const fileData: IFileInfo = { + fileName: "", + isNewFile: true, + isSaved: false, + fileUrl: undefined, + fileData: async () => `{"nextIndividualId":0,"objectPool":[],"labelPool":[],"behaviorPool":[]}` + } + + if (props.status) { + fileData.isNewFile = props.status.archive.isNewFile; + fileData.fileName = props.status.archive.fileName ?? ""; + fileData.isSaved = props.status.archive.isSaved; + fileData.fileUrl = props.status.archive.fileUrl; + } + + if (fileData.isNewFile) { + fileData.fileName = I18N(props, "Header.Bar.New.File.Name"); + } + + // 生成存档文件 + fileData.fileData = async () => { + return props.status?.archive.save(props.status.model) ?? ""; + }; + + const callBack = () => { + if (props.afterRunning) { + props.afterRunning(); + } + } + + return <> + { + props.setting?.platform === Platform.web ? + : + <> + } + +} + +const ArchiveSave = useSetting(useStatus(ArchiveSaveView)); + +export { ArchiveSave }; \ No newline at end of file diff --git a/source/Model/Archive.ts b/source/Model/Archive.ts index edf5577..c4328e4 100644 --- a/source/Model/Archive.ts +++ b/source/Model/Archive.ts @@ -22,7 +22,7 @@ interface IArchiveObject { behaviorPool: IArchiveBehavior[]; } -class Archive extends Emitter { +class Archive extends Emitter { /** * 是否为新文件 @@ -40,9 +40,9 @@ class Archive extends Emitter { public isSaved: boolean = false; /** - * 文件数据 + * 文件路径 */ - public fileData?: M; + public fileUrl?: string; /** * 将模型转换为存档对象