diff --git a/src/renderer/components/Editor.vue b/src/renderer/components/Editor.vue index d0c27564..00052144 100644 --- a/src/renderer/components/Editor.vue +++ b/src/renderer/components/Editor.vue @@ -71,7 +71,9 @@ export default defineComponent({ return } - if (!getSetting('auto-save', true)) { + const autoSave = getSetting('auto-save', 2000) + + if (!autoSave) { return } @@ -82,7 +84,7 @@ export default defineComponent({ } saveFile() - }, 2000) + }, autoSave) } async function changeFile (current?: Doc | null) { diff --git a/src/renderer/services/document.ts b/src/renderer/services/document.ts index c0c7cef1..29824b7e 100644 --- a/src/renderer/services/document.ts +++ b/src/renderer/services/document.ts @@ -1,3 +1,4 @@ +import { Fragment, h } from 'vue' import { Optional } from 'utility-types' import * as crypto from '@fe/utils/crypto' import { useModal } from '@fe/support/ui/modal' @@ -5,13 +6,13 @@ import { useToast } from '@fe/support/ui/toast' import store from '@fe/support/store' import type { Doc, PathItem } from '@fe/types' import { basename, dirname, isBelongTo, join, normalizeSep } from '@fe/utils/path' +import { getActionHandler } from '@fe/core/action' import { triggerHook } from '@fe/core/hook' import * as api from '@fe/support/api' import { getLogger } from '@fe/utils' import { getRepo, inputPassword, openPath, showItemInFolder } from './base' import { t } from './i18n' import { getSetting, setSetting } from './setting' -import { getActionHandler } from '@fe/core/action' const logger = getLogger('document') @@ -378,19 +379,56 @@ export async function ensureCurrentFileSaved () { return } + const unsaved = !store.getters.isSaved && currentFile.repo !== '__help__' + + if (!unsaved) { + return + } + + const fileURI = toUri(currentFile) + const checkFile = () => { + if (fileURI !== toUri(store.state.currentFile)) { + throw new Error('Save Error') + } + } + + const saveContent = async () => { + checkFile() + await saveDoc(currentFile, currentContent) + } + try { - if (isEncrypted(currentFile)) { - if (!store.getters.isSaved && !(await useModal().confirm({ - title: t('quit-check-dialog.title'), - content: t('quit-check-dialog.desc'), - }))) { - throw new Error('Please save document.') - } else { - store.commit('setCurrentFile', null) - } + const autoSave = !isEncrypted(currentFile) && getSetting('auto-save', 2000) + if (autoSave) { + await saveContent() } else { - if (currentFile && currentContent && currentFile.content !== currentContent && currentFile.repo !== '__help__') { - await saveDoc(currentFile, currentContent) + const confirm = await useModal().confirm({ + title: t('save-check-dialog.title'), + content: t('save-check-dialog.desc'), + action: h(Fragment, [ + h('button', { + onClick: async () => { + await saveContent() + useModal().ok() + } + }, t('save')), + h('button', { + onClick: () => useModal().ok() + }, t('discard')), + h('button', { + onClick: () => useModal().cancel() + }, t('cancel')), + ]) + }) + + checkFile() + + if (confirm) { + if (!store.getters.isSaved && currentFile.content) { + store.state.currentContent = currentFile.content! + } + } else { + throw new Error('Document not saved') } } } catch (error: any) { diff --git a/src/renderer/services/setting.ts b/src/renderer/services/setting.ts index 365c4e9f..f0246903 100644 --- a/src/renderer/services/setting.ts +++ b/src/renderer/services/setting.ts @@ -163,11 +163,15 @@ const schema: Schema = { required: true, }, 'auto-save': { - defaultValue: true, + defaultValue: 2000, title: 'T_setting-panel.schema.auto-save', - type: 'boolean', - format: 'checkbox', + enum: [0, 2000, 4000, 8000, 30000, 60000], + options: { + enum_titles: ['Disable', '2s', '4s', '8s', '30s', '60s'], + }, + type: 'number', group: 'editor', + required: true, }, shell: { defaultValue: '', diff --git a/src/renderer/types.ts b/src/renderer/types.ts index 10572964..63b38e2c 100644 --- a/src/renderer/types.ts +++ b/src/renderer/types.ts @@ -98,7 +98,7 @@ export type BuildInSettings = { 'repos': Repo[], 'theme': ThemeName, 'language': LanguageName, - 'auto-save': boolean, + 'auto-save': number, 'custom-css': string, 'assets-dir': string, 'shell': string, diff --git a/src/share/i18n/languages/en.ts b/src/share/i18n/languages/en.ts index 37723a58..8ac58f6b 100644 --- a/src/share/i18n/languages/en.ts +++ b/src/share/i18n/languages/en.ts @@ -24,6 +24,7 @@ const data = { 'no-password': 'No password was entered', 'save': 'Save', 'close': 'Close', + 'discard': 'Discard', 'edit': 'Edit', 'premium': { 'need-purchase': '[%s] Premium is required', @@ -139,6 +140,10 @@ const data = { 'discard': 'Discard Changes and exit', }, }, + 'save-check-dialog': { + 'title': 'Attention', + 'desc': 'The document has not been saved, do you want to save it?', + }, 'file-status': { 'unsaved': 'Unsaved', 'saving': 'Saving', diff --git a/src/share/i18n/languages/zh-CN.ts b/src/share/i18n/languages/zh-CN.ts index 17a5b45e..0200e393 100644 --- a/src/share/i18n/languages/zh-CN.ts +++ b/src/share/i18n/languages/zh-CN.ts @@ -26,6 +26,7 @@ const data: BaseLanguage = { 'save': '保存', 'close': '关闭', 'edit': '编辑', + 'discard': '放弃', 'premium': { 'need-purchase': '[%s] 需要高级版', 'buy-license': '立即购买', @@ -140,6 +141,10 @@ const data: BaseLanguage = { 'discard': '放弃保存并退出', }, }, + 'save-check-dialog': { + 'title': '提示', + 'desc': '文档尚未保存,是否要保存?', + }, 'file-status': { 'unsaved': '未保存', 'saving': '保存中',