Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b483092c68 | ||
|
|
bf75abc2f1 | ||
|
|
167e424568 | ||
|
|
64e54d0b0b | ||
|
|
33bfaa5959 | ||
|
|
9317871fdb | ||
|
|
a355bc07f4 | ||
|
|
ecd462fbd4 | ||
|
|
4de7a1d5f2 |
@@ -1,3 +1,37 @@
|
||||
## :tada: 2.3.1 (2022-11-13)
|
||||
|
||||
|
||||
### :sparkles: Features
|
||||
|
||||
* add $extName for paste template ([64e54d0](https://github.com/Molunerfinn/PicGo/commit/64e54d0)), closes [#1000](https://github.com/Molunerfinn/PicGo/issues/1000)
|
||||
|
||||
|
||||
### :bug: Bug Fixes
|
||||
|
||||
* upyun options is not required ([167e424](https://github.com/Molunerfinn/PicGo/commit/167e424)), closes [#1002](https://github.com/Molunerfinn/PicGo/issues/1002)
|
||||
|
||||
|
||||
|
||||
## :tada: 2.3.1-beta.8 (2022-10-30)
|
||||
|
||||
|
||||
### :sparkles: Features
|
||||
|
||||
* add remoteNotice ([9317871](https://github.com/Molunerfinn/PicGo/commit/9317871))
|
||||
* macOS tray icon more clearer ([ecd462f](https://github.com/Molunerfinn/PicGo/commit/ecd462f))
|
||||
|
||||
|
||||
### :bug: Bug Fixes
|
||||
|
||||
* url encode bug && copy-paste url encode bug ([4de7a1d](https://github.com/Molunerfinn/PicGo/commit/4de7a1d)), closes [#996](https://github.com/Molunerfinn/PicGo/issues/996)
|
||||
|
||||
|
||||
### :pencil: Documentation
|
||||
|
||||
* add PicHoro ([a355bc0](https://github.com/Molunerfinn/PicGo/commit/a355bc0))
|
||||
|
||||
|
||||
|
||||
## :tada: 2.3.1-beta.7 (2022-10-23)
|
||||
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ PicGo 本体支持如下图床:
|
||||
- 支持通过发送 HTTP 请求调用 PicGo 上传(v2.2.0+)
|
||||
- 更多功能等你自己去发现,同时也会不断开发新功能
|
||||
- 开发进度可以查看 [Projects](https://github.com/Molunerfinn/PicGo/projects),会同步更新开发进度
|
||||
- 欢迎加入 [官方讨论区](https://github.com/Molunerfinn/PicGo/discussions) 与我交流
|
||||
<!-- - 欢迎加入 [官方讨论区](https://github.com/Molunerfinn/PicGo/discussions) 与我交流 -->
|
||||
|
||||
**如果第一次使用,请参考应用 [使用文档](https://picgo.github.io/PicGo-Doc/zh/guide/getting-started.html)。遇到问题了还可以看看 [FAQ](https://github.com/Molunerfinn/PicGo/blob/dev/FAQ.md) 以及被关闭的 [issues](https://github.com/Molunerfinn/PicGo/issues?q=is%3Aissue+is%3Aclosed)。**
|
||||
|
||||
@@ -112,7 +112,8 @@ npm run electron:build
|
||||
## 其他相关
|
||||
|
||||
- [vs-picgo](https://github.com/PicGo/vs-picgo):PicGo 的 VS Code 版。
|
||||
- [flutter-picgo](https://github.com/PicGo/flutter-picgo):PicGo 的手机版(支持 Android 和 iOS )。
|
||||
- [flutter-picgo](https://github.com/PicGo/flutter-picgo):PicGo 的手机版 App(支持 Android 和 iOS )。
|
||||
- [PicHoro](https://github.com/Kuingsmile/PicHoro):另一款支持 PicGo 配置的手机版 App(暂时只支持 Android)。
|
||||
|
||||
## 赞助
|
||||
|
||||
@@ -130,4 +131,4 @@ npm run electron:build
|
||||
|
||||
[MIT](http://opensource.org/licenses/MIT)
|
||||
|
||||
Copyright (c) 2017 - 2019 Molunerfinn
|
||||
Copyright (c) 2017 - Now Molunerfinn
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "picgo",
|
||||
"version": "2.3.1-beta.7",
|
||||
"version": "2.3.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vue-cli-service electron:serve",
|
||||
@@ -48,7 +48,7 @@
|
||||
"keycode": "^2.2.0",
|
||||
"lodash-id": "^0.14.0",
|
||||
"lowdb": "^1.0.0",
|
||||
"picgo": "^1.5.0-alpha.10",
|
||||
"picgo": "^1.5.0",
|
||||
"qrcode.vue": "^1.7.0",
|
||||
"shell-path": "2.1.0",
|
||||
"uuidv4": "^6.2.11",
|
||||
|
||||
@@ -78,6 +78,7 @@ SETTINGS_MINI_WINDOW_ON_TOP: Mini Window On Top
|
||||
SETTINGS_AUTO_COPY_URL_AFTER_UPLOAD: Auto Copy URL After Upload
|
||||
SETTINGS_TIPS_PLACEHOLDER_URL: Use $url to represent url position
|
||||
SETTINGS_TIPS_PLACEHOLDER_FILENAME: Use $fileName to represent file name position
|
||||
SETTINGS_TIPS_PLACEHOLDER_EXTNAME: Use $extName to represent file's ext position
|
||||
SETTINGS_TIPS_SUCH_AS: 'Such as: $url/$fileName'
|
||||
SETTINGS_UPLOAD_PROXY: Upload Proxy
|
||||
SETTINGS_PLUGIN_INSTALL_PROXY: Proxy for Plugin Install
|
||||
@@ -156,7 +157,7 @@ PLUGIN_IMPORT_LOCAL: Import Local Plugins
|
||||
|
||||
TIPS_REMOVE_LINK: This operation will remove the picture from the album, continue?
|
||||
TIPS_WILL_REMOVE_CHOOSED_IMAGES: This operation will remove the picture from the album, continue?
|
||||
TIPS_MUST_CONTAINS_URL: Must contains $url
|
||||
TIPS_MUST_CONTAINS_URL: Must contains $url or $fileName or $extName
|
||||
TIPS_NETWORK_ERROR: Network Error
|
||||
TIPS_NEED_RELOAD: Need Reload App
|
||||
TIPS_PLEASE_CHOOSE_LOG_LEVEL: Please choose log level
|
||||
|
||||
@@ -78,6 +78,7 @@ SETTINGS_MINI_WINDOW_ON_TOP: Mini窗口置顶
|
||||
SETTINGS_AUTO_COPY_URL_AFTER_UPLOAD: 上传后自动复制URL
|
||||
SETTINGS_TIPS_PLACEHOLDER_URL: 用占位符 $url 来表示url的位置
|
||||
SETTINGS_TIPS_PLACEHOLDER_FILENAME: 用占位符 $fileName 来表示文件名的位置
|
||||
SETTINGS_TIPS_PLACEHOLDER_EXTNAME: 用占位符 $extName 来表示文件格式的位置
|
||||
SETTINGS_TIPS_SUCH_AS: 如
|
||||
SETTINGS_UPLOAD_PROXY: 上传代理
|
||||
SETTINGS_PLUGIN_INSTALL_PROXY: 插件安装代理
|
||||
@@ -156,7 +157,7 @@ PLUGIN_IMPORT_LOCAL: 导入本地插件
|
||||
|
||||
TIPS_REMOVE_LINK: 此操作将把该图片移出相册, 是否继续?
|
||||
TIPS_WILL_REMOVE_CHOOSED_IMAGES: 将在相册中移除刚才选中的 ${m} 张图片,是否继续?
|
||||
TIPS_MUST_CONTAINS_URL: 必须含有$url
|
||||
TIPS_MUST_CONTAINS_URL: 必须含有$url 或 $fileName 或 $extName
|
||||
TIPS_NETWORK_ERROR: 网络错误暂时无法获取
|
||||
TIPS_NEED_RELOAD: 需要重启生效
|
||||
TIPS_PLEASE_CHOOSE_LOG_LEVEL: 请选择日志记录等级
|
||||
|
||||
@@ -78,6 +78,7 @@ SETTINGS_MINI_WINDOW_ON_TOP: Mini視窗置頂
|
||||
SETTINGS_AUTO_COPY_URL_AFTER_UPLOAD: 上傳後自動複製URL
|
||||
SETTINGS_TIPS_PLACEHOLDER_URL: 用佔位符 $url 來表示URL的位置
|
||||
SETTINGS_TIPS_PLACEHOLDER_FILENAME: 用佔位符 $fileName 來表示檔案名稱的位置
|
||||
SETTINGS_TIPS_PLACEHOLDER_EXTNAME: 用佔位符 $extName 來表示檔案格式的位置
|
||||
SETTINGS_TIPS_SUCH_AS: 如
|
||||
SETTINGS_UPLOAD_PROXY: 上傳PROXY
|
||||
SETTINGS_PLUGIN_INSTALL_PROXY: 插件安裝PROXY
|
||||
@@ -156,7 +157,7 @@ PLUGIN_IMPORT_LOCAL: 導入本地插件
|
||||
|
||||
TIPS_REMOVE_LINK: 此操作將在相簿中移除該圖片,是否繼續?
|
||||
TIPS_WILL_REMOVE_CHOOSED_IMAGES: 將在相簿中移除剛才選中的 ${m} 張圖片,是否繼續?
|
||||
TIPS_MUST_CONTAINS_URL: 必須含有$url
|
||||
TIPS_MUST_CONTAINS_URL: 必須含有$url 或 $fileName 或 $extName
|
||||
TIPS_NETWORK_ERROR: 網路錯誤,暫時無法取得
|
||||
TIPS_NEED_RELOAD: 需要重新啟動生效
|
||||
TIPS_PLEASE_CHOOSE_LOG_LEVEL: 請選擇記錄等級
|
||||
|
||||
|
Before Width: | Height: | Size: 481 B After Width: | Height: | Size: 541 B |
|
Before Width: | Height: | Size: 807 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 20 KiB |
@@ -0,0 +1,199 @@
|
||||
// get notice from remote
|
||||
// such as some notices for users; some updates for users
|
||||
import fs from 'fs-extra'
|
||||
import { app, clipboard, dialog, shell } from 'electron'
|
||||
import { IRemoteNoticeActionType, IRemoteNoticeTriggerCount, IRemoteNoticeTriggerHook } from '#/types/enum'
|
||||
import { lte, gte } from 'semver'
|
||||
import path from 'path'
|
||||
|
||||
import axios from 'axios'
|
||||
import windowManager from '../window/windowManager'
|
||||
import { showNotification } from '~/main/utils/common'
|
||||
import { isDev } from '~/universal/utils/common'
|
||||
|
||||
// for test
|
||||
const REMOTE_NOTICE_URL = isDev ? 'http://localhost:8181/remote-notice.json' : 'https://picgo-1251750343.cos.accelerate.myqcloud.com/remote-notice.yml'
|
||||
|
||||
const REMOTE_NOTICE_LOCAL_STORAGE_FILE = 'picgo-remote-notice.json'
|
||||
|
||||
const STORE_PATH = app.getPath('userData')
|
||||
|
||||
const REMOTE_NOTICE_LOCAL_STORAGE_PATH = path.join(STORE_PATH, REMOTE_NOTICE_LOCAL_STORAGE_FILE)
|
||||
|
||||
class RemoteNoticeHandler {
|
||||
private remoteNotice: IRemoteNotice | null = null
|
||||
private remoteNoticeLocalCountStorage: IRemoteNoticeLocalCountStorage | null = null
|
||||
|
||||
async init () {
|
||||
this.remoteNotice = await this.getRemoteNoticeInfo()
|
||||
this.initLocalCountStorage()
|
||||
}
|
||||
|
||||
private initLocalCountStorage () {
|
||||
const localCountStorage = {}
|
||||
if (!fs.existsSync(REMOTE_NOTICE_LOCAL_STORAGE_PATH)) {
|
||||
fs.writeFileSync(REMOTE_NOTICE_LOCAL_STORAGE_PATH, JSON.stringify({}))
|
||||
}
|
||||
try {
|
||||
const localCountStorage: IRemoteNoticeLocalCountStorage = fs.readJSONSync(REMOTE_NOTICE_LOCAL_STORAGE_PATH, 'utf8')
|
||||
this.remoteNoticeLocalCountStorage = localCountStorage
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
this.remoteNoticeLocalCountStorage = localCountStorage
|
||||
}
|
||||
}
|
||||
|
||||
private saveLocalCountStorage (newData?: IRemoteNoticeLocalCountStorage) {
|
||||
if (newData) {
|
||||
this.remoteNoticeLocalCountStorage = newData
|
||||
}
|
||||
fs.writeFileSync(REMOTE_NOTICE_LOCAL_STORAGE_PATH, JSON.stringify(this.remoteNoticeLocalCountStorage))
|
||||
}
|
||||
|
||||
private async getRemoteNoticeInfo (): Promise<IRemoteNotice | null> {
|
||||
try {
|
||||
const noticeInfo = await axios({
|
||||
method: 'get',
|
||||
url: REMOTE_NOTICE_URL,
|
||||
responseType: 'json'
|
||||
}).then(res => res.data) as IRemoteNotice
|
||||
return noticeInfo
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* if the notice is not shown or is always shown, then show the notice
|
||||
* @param action
|
||||
*/
|
||||
private checkActionCount (action: IRemoteNoticeAction) {
|
||||
try {
|
||||
if (!this.remoteNoticeLocalCountStorage) {
|
||||
return true
|
||||
}
|
||||
const actionCount = this.remoteNoticeLocalCountStorage[action.id]
|
||||
if (actionCount === undefined) {
|
||||
if (action.triggerCount === IRemoteNoticeTriggerCount.ALWAYS) {
|
||||
this.remoteNoticeLocalCountStorage[action.id] = 1 // if always, count number
|
||||
} else {
|
||||
this.remoteNoticeLocalCountStorage[action.id] = true
|
||||
}
|
||||
return true
|
||||
} else {
|
||||
// here is the count of action
|
||||
// if not always show, then can't show
|
||||
if (action.triggerCount !== IRemoteNoticeTriggerCount.ALWAYS) {
|
||||
return false
|
||||
} else {
|
||||
const preCount = this.remoteNoticeLocalCountStorage[action.id]
|
||||
if (typeof preCount !== 'number') {
|
||||
this.remoteNoticeLocalCountStorage[action.id] = true
|
||||
return true
|
||||
} else {
|
||||
this.remoteNoticeLocalCountStorage[action.id] = preCount + 1
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
this.saveLocalCountStorage()
|
||||
}
|
||||
}
|
||||
|
||||
private async doActions (actions: IRemoteNoticeAction[]) {
|
||||
for (const action of actions) {
|
||||
if (this.checkActionCount(action)) {
|
||||
switch (action.type) {
|
||||
case IRemoteNoticeActionType.SHOW_DIALOG: {
|
||||
// SHOW DIALOG
|
||||
const currentWindow = windowManager.getAvailableWindow()
|
||||
dialog.showOpenDialog(currentWindow, action.data?.options)
|
||||
break
|
||||
}
|
||||
case IRemoteNoticeActionType.SHOW_NOTICE:
|
||||
showNotification({
|
||||
title: action.data?.title || '',
|
||||
body: action.data?.content || '',
|
||||
clickToCopy: !!action.data?.copyToClipboard,
|
||||
copyContent: action.data?.copyToClipboard || '',
|
||||
clickFn () {
|
||||
if (action.data?.url) {
|
||||
shell.openExternal(action.data.url)
|
||||
}
|
||||
}
|
||||
})
|
||||
break
|
||||
case IRemoteNoticeActionType.OPEN_URL:
|
||||
// OPEN URL
|
||||
shell.openExternal(action.data?.url || '')
|
||||
break
|
||||
case IRemoteNoticeActionType.COMMON:
|
||||
// DO COMMON CASE
|
||||
if (action.data?.copyToClipboard) {
|
||||
clipboard.writeText(action.data.copyToClipboard)
|
||||
}
|
||||
if (action.data?.url) {
|
||||
shell.openExternal(action.data.url)
|
||||
}
|
||||
break
|
||||
case IRemoteNoticeActionType.SHOW_MESSAGE_BOX: {
|
||||
const currentWindow = windowManager.getAvailableWindow()
|
||||
dialog.showMessageBox(currentWindow, {
|
||||
title: action.data?.title || '',
|
||||
message: action.data?.content || '',
|
||||
type: 'info',
|
||||
buttons: action.data?.buttons?.map(item => item.label) || ['Yes']
|
||||
}).then(res => {
|
||||
const button = action.data?.buttons?.[res.response]
|
||||
if (button?.type === 'cancel') {
|
||||
// do nothing
|
||||
} else {
|
||||
if (button?.action) {
|
||||
this.doActions([button?.action])
|
||||
}
|
||||
}
|
||||
})
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
triggerHook (hook: IRemoteNoticeTriggerHook) {
|
||||
if (!this.remoteNotice || !this.remoteNotice.list) {
|
||||
return
|
||||
}
|
||||
const actions = this.remoteNotice.list
|
||||
.filter(item => {
|
||||
if (item.versionMatch) {
|
||||
switch (item.versionMatch) {
|
||||
case 'exact':
|
||||
return item.versions.includes(app.getVersion())
|
||||
case 'gte':
|
||||
return item.versions.some(version => {
|
||||
// appVersion >= version
|
||||
return gte(app.getVersion(), version)
|
||||
})
|
||||
case 'lte':
|
||||
return item.versions.some(version => {
|
||||
// appVersion <= version
|
||||
return lte(app.getVersion(), version)
|
||||
})
|
||||
}
|
||||
}
|
||||
return item.versions.includes(app.getVersion())
|
||||
})
|
||||
.map(item => item.actions)
|
||||
.reduce((pre, cur) => pre.concat(cur), [])
|
||||
.filter(item => item.hooks.includes(hook))
|
||||
this.doActions(actions)
|
||||
}
|
||||
}
|
||||
|
||||
const remoteNoticeHandler = new RemoteNoticeHandler()
|
||||
|
||||
export {
|
||||
remoteNoticeHandler
|
||||
}
|
||||
@@ -4,12 +4,13 @@ import {
|
||||
MINI_WINDOW_URL,
|
||||
RENAME_WINDOW_URL
|
||||
} from './constants'
|
||||
import { IWindowList } from '#/types/enum'
|
||||
import { IRemoteNoticeTriggerHook, IWindowList } from '#/types/enum'
|
||||
import bus from '@core/bus'
|
||||
import { CREATE_APP_MENU } from '@core/bus/constants'
|
||||
import db from '~/main/apis/core/datastore'
|
||||
import { TOGGLE_SHORTKEY_MODIFIED_MODE } from '#/events/constants'
|
||||
import { app } from 'electron'
|
||||
import { remoteNoticeHandler } from '../remoteNotice'
|
||||
// import { i18n } from '~/main/i18n'
|
||||
// import { URLSearchParams } from 'url'
|
||||
|
||||
@@ -88,6 +89,9 @@ windowList.set(IWindowList.SETTING_WINDOW, {
|
||||
return options
|
||||
},
|
||||
callback (window, windowManager) {
|
||||
window.once('show', () => {
|
||||
remoteNoticeHandler.triggerHook(IRemoteNoticeTriggerHook.SETTING_WINDOW_OPEN)
|
||||
})
|
||||
window.loadURL(handleWindowParams(SETTING_WINDOW_URL))
|
||||
window.on('closed', () => {
|
||||
bus.emit(TOGGLE_SHORTKEY_MODIFIED_MODE, false)
|
||||
|
||||
@@ -12,7 +12,7 @@ import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer'
|
||||
import beforeOpen from '~/main/utils/beforeOpen'
|
||||
import ipcList from '~/main/events/ipcList'
|
||||
import busEventList from '~/main/events/busEventList'
|
||||
import { IWindowList } from '#/types/enum'
|
||||
import { IRemoteNoticeTriggerHook, IWindowList } from '#/types/enum'
|
||||
import windowManager from 'apis/app/window/windowManager'
|
||||
import {
|
||||
updateShortKeyFromVersion212,
|
||||
@@ -35,6 +35,7 @@ import logger from 'apis/core/picgo/logger'
|
||||
import picgo from 'apis/core/picgo'
|
||||
import fixPath from './fixPath'
|
||||
import { initI18n } from '~/main/utils/handleI18n'
|
||||
import { remoteNoticeHandler } from 'apis/app/remoteNotice'
|
||||
|
||||
const isDevelopment = process.env.NODE_ENV !== 'production'
|
||||
|
||||
@@ -101,6 +102,8 @@ class LifeCycle {
|
||||
notice.show()
|
||||
}
|
||||
}
|
||||
await remoteNoticeHandler.init()
|
||||
remoteNoticeHandler.triggerHook(IRemoteNoticeTriggerHook.APP_START)
|
||||
}
|
||||
if (!app.isReady()) {
|
||||
app.on('ready', readyFunction)
|
||||
|
||||
@@ -45,7 +45,7 @@ class Server {
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
if (request.method === 'POST') {
|
||||
if (!routers.getHandler(request.url!)) {
|
||||
logger.warn(`[PicGo Server] don't support [${request.url}] url`)
|
||||
|
||||
@@ -15,7 +15,9 @@ export const handleCopyUrl = (str: string): void => {
|
||||
export const showNotification = (options: IPrivateShowNotificationOption = {
|
||||
title: '',
|
||||
body: '',
|
||||
clickToCopy: false
|
||||
clickToCopy: false,
|
||||
copyContent: '',
|
||||
clickFn: () => {}
|
||||
}) => {
|
||||
const notification = new Notification({
|
||||
title: options.title,
|
||||
@@ -24,7 +26,10 @@ export const showNotification = (options: IPrivateShowNotificationOption = {
|
||||
})
|
||||
const handleClick = () => {
|
||||
if (options.clickToCopy) {
|
||||
clipboard.writeText(options.body)
|
||||
clipboard.writeText(options.copyContent || options.body)
|
||||
}
|
||||
if (options.clickFn) {
|
||||
options.clickFn()
|
||||
}
|
||||
}
|
||||
notification.once('click', handleClick)
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
import { IPasteStyle } from '#/types/enum'
|
||||
import { handleUrlEncode } from '#/utils/common'
|
||||
|
||||
const formatCustomLink = (customLink: string, item: ImgInfo) => {
|
||||
const fileName = item.fileName!.replace(new RegExp(`\\${item.extname}$`), '')
|
||||
const url = item.url || item.imgUrl
|
||||
const extName = item.extname
|
||||
const formatObj = {
|
||||
url,
|
||||
fileName
|
||||
fileName,
|
||||
extName
|
||||
}
|
||||
const keys = Object.keys(formatObj) as ['url', 'fileName']
|
||||
const keys = Object.keys(formatObj) as ['url', 'fileName', 'extName']
|
||||
keys.forEach(item => {
|
||||
if (customLink.indexOf(`$${item}`) !== -1) {
|
||||
const reg = new RegExp(`\\$${item}`, 'g')
|
||||
@@ -18,7 +21,7 @@ const formatCustomLink = (customLink: string, item: ImgInfo) => {
|
||||
}
|
||||
|
||||
export default (style: IPasteStyle, item: ImgInfo, customLink: string | undefined) => {
|
||||
const url = item.url || item.imgUrl
|
||||
const url = handleUrlEncode(item.url || item.imgUrl)
|
||||
const _customLink = customLink || '$url'
|
||||
const tpl = {
|
||||
markdown: ``,
|
||||
|
||||
@@ -201,6 +201,9 @@
|
||||
<div class="custom-title">
|
||||
{{ $T('SETTINGS_TIPS_PLACEHOLDER_FILENAME') }}
|
||||
</div>
|
||||
<div class="custom-title">
|
||||
{{ $T('SETTINGS_TIPS_PLACEHOLDER_EXTNAME') }}
|
||||
</div>
|
||||
<el-input
|
||||
class="align-center"
|
||||
v-model="customLink.value"
|
||||
@@ -226,7 +229,6 @@
|
||||
label-position="right"
|
||||
:model="customLink"
|
||||
ref="customLink"
|
||||
:rules="rules"
|
||||
label-width="120px"
|
||||
>
|
||||
<el-form-item
|
||||
@@ -397,7 +399,7 @@ import { getLatestVersion } from '#/utils/getLatestVersion'
|
||||
import { compare } from 'compare-versions'
|
||||
import { STABLE_RELEASE_URL, BETA_RELEASE_URL } from '#/utils/static'
|
||||
const customLinkRule = (rule: string, value: string, callback: (arg0?: Error) => void) => {
|
||||
if (!/\$url/.test(value)) {
|
||||
if (!/\$url/.test(value) && !/\$fileName/.test(value) && !/\$extName/.test(value)) {
|
||||
return callback(new Error(T('TIPS_MUST_CONTAINS_URL')))
|
||||
} else {
|
||||
return callback()
|
||||
|
||||
@@ -27,3 +27,22 @@ export enum IWindowList {
|
||||
MINI_WINDOW = 'MINI_WINDOW',
|
||||
RENAME_WINDOW = 'RENAME_WINDOW'
|
||||
}
|
||||
|
||||
export enum IRemoteNoticeActionType {
|
||||
OPEN_URL = 'OPEN_URL',
|
||||
SHOW_NOTICE = 'SHOW_NOTICE', // notification
|
||||
SHOW_DIALOG = 'SHOW_DIALOG', // dialog notice
|
||||
COMMON = 'COMMON',
|
||||
VOID = 'VOID', // do nothing
|
||||
SHOW_MESSAGE_BOX = 'SHOW_MESSAGE_BOX'
|
||||
}
|
||||
|
||||
export enum IRemoteNoticeTriggerHook {
|
||||
APP_START = 'APP_START',
|
||||
SETTING_WINDOW_OPEN = 'SETTING_WINDOW_OPEN',
|
||||
}
|
||||
|
||||
export enum IRemoteNoticeTriggerCount {
|
||||
ONCE = 'ONCE', // default
|
||||
ALWAYS = 'ALWAYS'
|
||||
}
|
||||
|
||||
@@ -73,6 +73,7 @@ interface ILocales {
|
||||
SETTINGS_AUTO_COPY_URL_AFTER_UPLOAD: string
|
||||
SETTINGS_TIPS_PLACEHOLDER_URL: string
|
||||
SETTINGS_TIPS_PLACEHOLDER_FILENAME: string
|
||||
SETTINGS_TIPS_PLACEHOLDER_EXTNAME: string
|
||||
SETTINGS_TIPS_SUCH_AS: string
|
||||
SETTINGS_UPLOAD_PROXY: string
|
||||
SETTINGS_PLUGIN_INSTALL_PROXY: string
|
||||
|
||||
@@ -219,6 +219,8 @@ interface IPrivateShowNotificationOption extends IShowNotificationOption{
|
||||
* click notification to copy the body
|
||||
*/
|
||||
clickToCopy?: boolean
|
||||
copyContent?: string // something to copy
|
||||
clickFn?: () => void
|
||||
}
|
||||
|
||||
interface IShowMessageBoxOption {
|
||||
@@ -348,3 +350,42 @@ interface II18nItem {
|
||||
label: string
|
||||
value: string
|
||||
}
|
||||
|
||||
interface IRemoteNotice {
|
||||
version: number
|
||||
list: Array<{
|
||||
versions: string[] // matched picgo version
|
||||
actions: IRemoteNoticeAction[]
|
||||
versionMatch?: 'exact' | 'gte' | 'lte'
|
||||
}>
|
||||
}
|
||||
|
||||
interface IRemoteNoticeAction {
|
||||
type: import('#/types/enum').IRemoteNoticeActionType
|
||||
// trigger time
|
||||
hooks: import('#/types/enum').IRemoteNoticeTriggerHook[]
|
||||
id: string
|
||||
// trigger count: always or once; default: once
|
||||
triggerCount: import('#/types/enum').IRemoteNoticeTriggerCount
|
||||
|
||||
data?: {
|
||||
title?: string
|
||||
content?: string
|
||||
desc?: string // action desc
|
||||
buttons?: IRemoteNoticeButton[]
|
||||
url?: string
|
||||
copyToClipboard?: string
|
||||
options: any // for other case
|
||||
}
|
||||
}
|
||||
|
||||
interface IRemoteNoticeButton {
|
||||
label: string
|
||||
labelEN?: string
|
||||
type: 'confirm' | 'cancel' | 'other'
|
||||
action: IRemoteNoticeAction
|
||||
}
|
||||
|
||||
interface IRemoteNoticeLocalCountStorage {
|
||||
[id: string]: true | number
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ export const isUrl = (url: string): boolean => (url.startsWith('http://') || url
|
||||
export const isUrlEncode = (url: string): boolean => {
|
||||
url = url || ''
|
||||
try {
|
||||
return url !== decodeURIComponent(url)
|
||||
return url !== decodeURI(url)
|
||||
} catch (e) {
|
||||
// if some error caught, try to let it go
|
||||
return true
|
||||
@@ -11,7 +11,7 @@ export const isUrlEncode = (url: string): boolean => {
|
||||
|
||||
export const handleUrlEncode = (url: string): string => {
|
||||
if (!isUrlEncode(url)) {
|
||||
url = encodeURIComponent(url)
|
||||
url = encodeURI(url)
|
||||
}
|
||||
return url
|
||||
}
|
||||
@@ -41,3 +41,5 @@ export const simpleClone = (obj: any) => {
|
||||
export const enforceNumber = (num: number | string) => {
|
||||
return isNaN(Number(num)) ? 0 : Number(num)
|
||||
}
|
||||
|
||||
export const isDev = process.env.NODE_ENV === 'development'
|
||||
|
||||
@@ -9919,10 +9919,10 @@ performance-now@^2.1.0:
|
||||
resolved "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
|
||||
integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
|
||||
|
||||
picgo@^1.5.0-alpha.10:
|
||||
version "1.5.0-alpha.10"
|
||||
resolved "https://registry.npmjs.org/picgo/-/picgo-1.5.0-alpha.10.tgz#fd567ac60c831395d5f16b80cf59646cab492c9a"
|
||||
integrity sha512-uFVFXxocbqXyc3lpGGIY2Sn55osXZWrTsNh9/CBSgJSqRVkp13nYnLMffZTp2+zzd/mDTpdqf/AUuEFI9dho+A==
|
||||
picgo@^1.5.0:
|
||||
version "1.5.0"
|
||||
resolved "https://registry.npmmirror.com/picgo/-/picgo-1.5.0.tgz#c7ac682253580148c8748efd54b788f98f939d39"
|
||||
integrity sha512-4OB5s9ywXbY+ipjV1Rmb4mzvtrIEaU9c/ZdVFHM0cfLhQBJD3ghYbn6lWI3qtrC/ScJvnrCo7f8fCAFzFvH2NQ==
|
||||
dependencies:
|
||||
"@picgo/i18n" "^1.0.0"
|
||||
"@picgo/store" "^2.0.2"
|
||||
|
||||