feat: check update
This commit is contained in:
parent
80e34688b1
commit
e962351b13
@ -1,3 +1,6 @@
|
|||||||
provider: generic
|
# provider: generic
|
||||||
url: http://127.0.0.1:8080
|
# url: http://127.0.0.1:8080
|
||||||
updaterCacheDirName: cherry-studio-updater
|
# updaterCacheDirName: cherry-studio-updater
|
||||||
|
provider: github
|
||||||
|
repo: cherry-studio
|
||||||
|
owner: kangfenmao
|
||||||
|
|||||||
@ -56,7 +56,5 @@ electronDownload:
|
|||||||
afterSign: scripts/notarize.js
|
afterSign: scripts/notarize.js
|
||||||
releaseInfo:
|
releaseInfo:
|
||||||
releaseNotes: |
|
releaseNotes: |
|
||||||
- 修复多语言提示错误
|
- 修复更新日志页面不能滚动问题
|
||||||
- 修复智谱AI默认模型错误问题
|
- 新增检查更新按钮
|
||||||
- 修复 OpenRouter API 检测出错问题
|
|
||||||
- 修复模型提供商多语言翻译错误问题
|
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
import { electronApp, is, optimizer } from '@electron-toolkit/utils'
|
import { electronApp, is, optimizer } from '@electron-toolkit/utils'
|
||||||
|
import * as Sentry from '@sentry/electron/main'
|
||||||
import { app, BrowserWindow, ipcMain, Menu, MenuItem, shell } from 'electron'
|
import { app, BrowserWindow, ipcMain, Menu, MenuItem, shell } from 'electron'
|
||||||
|
import installExtension, { REDUX_DEVTOOLS } from 'electron-devtools-installer'
|
||||||
import windowStateKeeper from 'electron-window-state'
|
import windowStateKeeper from 'electron-window-state'
|
||||||
import { join } from 'path'
|
import { join } from 'path'
|
||||||
import icon from '../../resources/icon.png?asset'
|
import icon from '../../resources/icon.png?asset'
|
||||||
import installExtension, { REDUX_DEVTOOLS } from 'electron-devtools-installer'
|
|
||||||
import AppUpdater from './updater'
|
import AppUpdater from './updater'
|
||||||
import * as Sentry from '@sentry/electron/main'
|
|
||||||
|
|
||||||
function createWindow(): void {
|
function createWindow() {
|
||||||
// Load the previous state with fallback to defaults
|
// Load the previous state with fallback to defaults
|
||||||
const mainWindowState = windowStateKeeper({
|
const mainWindowState = windowStateKeeper({
|
||||||
defaultWidth: 1080,
|
defaultWidth: 1080,
|
||||||
@ -62,6 +62,8 @@ function createWindow(): void {
|
|||||||
} else {
|
} else {
|
||||||
mainWindow.loadFile(join(__dirname, '../renderer/index.html'))
|
mainWindow.loadFile(join(__dirname, '../renderer/index.html'))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return mainWindow
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method will be called when Electron has finished
|
// This method will be called when Electron has finished
|
||||||
@ -78,26 +80,36 @@ app.whenReady().then(() => {
|
|||||||
optimizer.watchWindowShortcuts(window)
|
optimizer.watchWindowShortcuts(window)
|
||||||
})
|
})
|
||||||
|
|
||||||
// IPC
|
|
||||||
ipcMain.handle('get-app-info', () => ({
|
|
||||||
version: app.getVersion()
|
|
||||||
}))
|
|
||||||
|
|
||||||
createWindow()
|
|
||||||
|
|
||||||
app.on('activate', function () {
|
app.on('activate', function () {
|
||||||
// On macOS it's common to re-create a window in the app when the
|
// On macOS it's common to re-create a window in the app when the
|
||||||
// dock icon is clicked and there are no other windows open.
|
// dock icon is clicked and there are no other windows open.
|
||||||
if (BrowserWindow.getAllWindows().length === 0) createWindow()
|
if (BrowserWindow.getAllWindows().length === 0) createWindow()
|
||||||
})
|
})
|
||||||
|
|
||||||
installExtension(REDUX_DEVTOOLS)
|
const mainWindow = createWindow()
|
||||||
.then((name) => console.log(`Added Extension: ${name}`))
|
|
||||||
.catch((err) => console.log('An error occurred: ', err))
|
|
||||||
|
|
||||||
if (app.isPackaged) {
|
const { autoUpdater } = new AppUpdater(mainWindow)
|
||||||
setTimeout(() => new AppUpdater(), 3000)
|
|
||||||
}
|
// IPC
|
||||||
|
ipcMain.handle('get-app-info', () => ({
|
||||||
|
version: app.getVersion(),
|
||||||
|
isPackaged: app.isPackaged
|
||||||
|
}))
|
||||||
|
|
||||||
|
ipcMain.handle('open-website', (_, url: string) => {
|
||||||
|
shell.openExternal(url)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 触发检查更新(此方法用于被渲染线程调用,例如页面点击检查更新按钮来调用此方法)
|
||||||
|
ipcMain.handle('check-for-update', async () => {
|
||||||
|
autoUpdater.logger?.info('触发检查更新')
|
||||||
|
return {
|
||||||
|
currentVersion: autoUpdater.currentVersion,
|
||||||
|
update: await autoUpdater.checkForUpdates()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
installExtension(REDUX_DEVTOOLS)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Quit when all windows are closed, except on macOS. There, it's common
|
// Quit when all windows are closed, except on macOS. There, it's common
|
||||||
|
|||||||
@ -1,24 +1,20 @@
|
|||||||
import { autoUpdater, UpdateInfo } from 'electron-updater'
|
import { AppUpdater as _AppUpdater, autoUpdater, UpdateInfo } from 'electron-updater'
|
||||||
import logger from 'electron-log'
|
import logger from 'electron-log'
|
||||||
import { dialog, ipcMain } from 'electron'
|
import { BrowserWindow, dialog } from 'electron'
|
||||||
|
|
||||||
export default class AppUpdater {
|
export default class AppUpdater {
|
||||||
constructor() {
|
autoUpdater: _AppUpdater = autoUpdater
|
||||||
|
|
||||||
|
constructor(mainWindow: BrowserWindow) {
|
||||||
logger.transports.file.level = 'debug'
|
logger.transports.file.level = 'debug'
|
||||||
autoUpdater.logger = logger
|
autoUpdater.logger = logger
|
||||||
autoUpdater.forceDevUpdateConfig = true
|
autoUpdater.forceDevUpdateConfig = true
|
||||||
autoUpdater.autoDownload = false
|
autoUpdater.autoDownload = false
|
||||||
autoUpdater.checkForUpdates()
|
|
||||||
|
|
||||||
// 触发检查更新(此方法用于被渲染线程调用,例如页面点击检查更新按钮来调用此方法)
|
|
||||||
ipcMain.on('check-for-update', () => {
|
|
||||||
logger.info('触发检查更新')
|
|
||||||
return autoUpdater.checkForUpdates()
|
|
||||||
})
|
|
||||||
|
|
||||||
// 检测下载错误
|
// 检测下载错误
|
||||||
autoUpdater.on('error', (error) => {
|
autoUpdater.on('error', (error) => {
|
||||||
logger.error('更新异常', error)
|
logger.error('更新异常', error)
|
||||||
|
mainWindow.webContents.send('update-error', error)
|
||||||
})
|
})
|
||||||
|
|
||||||
// 检测是否需要更新
|
// 检测是否需要更新
|
||||||
@ -28,6 +24,7 @@ export default class AppUpdater {
|
|||||||
|
|
||||||
autoUpdater.on('update-available', (releaseInfo: UpdateInfo) => {
|
autoUpdater.on('update-available', (releaseInfo: UpdateInfo) => {
|
||||||
autoUpdater.logger?.info('检测到新版本,确认是否下载')
|
autoUpdater.logger?.info('检测到新版本,确认是否下载')
|
||||||
|
mainWindow.webContents.send('update-available', releaseInfo)
|
||||||
const releaseNotes = releaseInfo.releaseNotes
|
const releaseNotes = releaseInfo.releaseNotes
|
||||||
let releaseContent = ''
|
let releaseContent = ''
|
||||||
if (releaseNotes) {
|
if (releaseNotes) {
|
||||||
@ -49,10 +46,12 @@ export default class AppUpdater {
|
|||||||
title: '应用有新的更新',
|
title: '应用有新的更新',
|
||||||
detail: releaseContent,
|
detail: releaseContent,
|
||||||
message: '发现新版本,是否现在更新?',
|
message: '发现新版本,是否现在更新?',
|
||||||
buttons: ['否', '是']
|
buttons: ['下次再说', '更新']
|
||||||
})
|
})
|
||||||
.then(({ response }) => {
|
.then(({ response }) => {
|
||||||
if (response === 1) {
|
if (response === 1) {
|
||||||
|
logger.info('用户选择更新,准备下载更新')
|
||||||
|
mainWindow.webContents.send('download-update')
|
||||||
autoUpdater.downloadUpdate()
|
autoUpdater.downloadUpdate()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -61,11 +60,13 @@ export default class AppUpdater {
|
|||||||
// 检测到不需要更新时
|
// 检测到不需要更新时
|
||||||
autoUpdater.on('update-not-available', () => {
|
autoUpdater.on('update-not-available', () => {
|
||||||
logger.info('现在使用的就是最新版本,不用更新')
|
logger.info('现在使用的就是最新版本,不用更新')
|
||||||
|
mainWindow.webContents.send('update-not-available')
|
||||||
})
|
})
|
||||||
|
|
||||||
// 更新下载进度
|
// 更新下载进度
|
||||||
autoUpdater.on('download-progress', (progress) => {
|
autoUpdater.on('download-progress', (progress) => {
|
||||||
logger.info('下载进度', progress)
|
logger.info('下载进度', progress)
|
||||||
|
mainWindow.webContents.send('download-progress', progress)
|
||||||
})
|
})
|
||||||
|
|
||||||
// 当需要更新的内容下载完成后
|
// 当需要更新的内容下载完成后
|
||||||
@ -80,5 +81,7 @@ export default class AppUpdater {
|
|||||||
setImmediate(() => autoUpdater.quitAndInstall())
|
setImmediate(() => autoUpdater.quitAndInstall())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this.autoUpdater = autoUpdater
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
3
src/preload/index.d.ts
vendored
3
src/preload/index.d.ts
vendored
@ -6,7 +6,10 @@ declare global {
|
|||||||
api: {
|
api: {
|
||||||
getAppInfo: () => Promise<{
|
getAppInfo: () => Promise<{
|
||||||
version: string
|
version: string
|
||||||
|
isPackaged: boolean
|
||||||
}>
|
}>
|
||||||
|
checkForUpdate: () => void
|
||||||
|
openWebsite: (url: string) => void
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,8 @@ import { electronAPI } from '@electron-toolkit/preload'
|
|||||||
// Custom APIs for renderer
|
// Custom APIs for renderer
|
||||||
const api = {
|
const api = {
|
||||||
getAppInfo: () => ipcRenderer.invoke('get-app-info'),
|
getAppInfo: () => ipcRenderer.invoke('get-app-info'),
|
||||||
checkForUpdate: () => ipcRenderer.invoke('check-for-update')
|
checkForUpdate: () => ipcRenderer.invoke('check-for-update'),
|
||||||
|
openWebsite: (url: string) => ipcRenderer.invoke('open-website', url)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use `contextBridge` APIs to expose Electron APIs to
|
// Use `contextBridge` APIs to expose Electron APIs to
|
||||||
|
|||||||
@ -1,20 +1,25 @@
|
|||||||
# CHANGES LOG
|
# CHANGES LOG
|
||||||
|
|
||||||
|
### v0.2.4 - 2024-07-16
|
||||||
|
|
||||||
|
- Fixed the issue of the update log page cannot be scrolled
|
||||||
|
- Added a check for updates button
|
||||||
|
|
||||||
### v0.2.3 - 2024-07-16
|
### v0.2.3 - 2024-07-16
|
||||||
|
|
||||||
1. Fixed multi-language prompt errors
|
- Fixed multi-language prompt errors
|
||||||
2. Fixed default model error issues with ZHIPU AI
|
- Fixed default model error issues with ZHIPU AI
|
||||||
3. Fixed OpenRouter API detection error issues
|
- Fixed OpenRouter API detection error issues
|
||||||
4. Fixed multi-language translation errors with model providers
|
- Fixed multi-language translation errors with model providers
|
||||||
|
|
||||||
### v0.2.2 - 2024-07-15
|
### v0.2.2 - 2024-07-15
|
||||||
|
|
||||||
1. Fix the issue where the default assistant name is empty.
|
- Fix the issue where the default assistant name is empty.
|
||||||
2. Fix the problem with default language detection during the first installation.
|
- Fix the problem with default language detection during the first installation.
|
||||||
3. Adjust the changelog style.
|
- Adjust the changelog style.
|
||||||
|
|
||||||
### v0.2.1 - 2024-07-15
|
### v0.2.1 - 2024-07-15
|
||||||
|
|
||||||
1. **Feature**: Add new feature for pausing message sending
|
- **Feature**: Add new feature for pausing message sending
|
||||||
2. **Fix**: Resolve incomplete translation issue upon language switch
|
- **Fix**: Resolve incomplete translation issue upon language switch
|
||||||
3. **Build**: Support for macOS Intel architecture
|
- **Build**: Support for macOS Intel architecture
|
||||||
|
|||||||
@ -1,21 +1,26 @@
|
|||||||
# 更新日志
|
# 更新日志
|
||||||
|
|
||||||
|
### v0.2.4 - 2024-07-16
|
||||||
|
|
||||||
|
- 修复更新日志页面不能滚动问题
|
||||||
|
- 新增检查更新按钮
|
||||||
|
|
||||||
### v0.2.3 - 2024-07-16
|
### v0.2.3 - 2024-07-16
|
||||||
|
|
||||||
1. 修复多语言提示错误
|
- 修复多语言提示错误
|
||||||
2. 修复智谱AI默认模型错误问题
|
- 修复智谱AI默认模型错误问题
|
||||||
3. 修复 OpenRouter API 检测出错问题
|
- 修复 OpenRouter API 检测出错问题
|
||||||
4. 修复模型提供商多语言翻译错误问题
|
- 修复模型提供商多语言翻译错误问题
|
||||||
|
|
||||||
### v0.2.2 - 2024-07-15
|
### v0.2.2 - 2024-07-15
|
||||||
|
|
||||||
1. 修复默认助理名称为空的问题
|
- 修复默认助理名称为空的问题
|
||||||
2. 修复首次安装默认语言检测问题
|
- 修复首次安装默认语言检测问题
|
||||||
3. 更新日志样式微调
|
- 更新日志样式微调
|
||||||
|
|
||||||
### v0.2.1 - 2024-07-15
|
### v0.2.1 - 2024-07-15
|
||||||
|
|
||||||
1. 【功能】新增消息暂停发送功能
|
- 【功能】新增消息暂停发送功能
|
||||||
2. 【修复】修复多语言切换不彻底问题
|
- 【修复】修复多语言切换不彻底问题
|
||||||
3. 【构建】支持 macOS Intel 架构
|
- 【构建】支持 macOS Intel 架构
|
||||||
|
|
||||||
|
|||||||
@ -15,4 +15,11 @@ export function useAppInitEffect() {
|
|||||||
})
|
})
|
||||||
i18nInit()
|
i18nInit()
|
||||||
}, [dispatch])
|
}, [dispatch])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
runAsyncFunction(async () => {
|
||||||
|
const { isPackaged } = await window.api.getAppInfo()
|
||||||
|
isPackaged && setTimeout(window.api.checkForUpdate, 3000)
|
||||||
|
})
|
||||||
|
}, [])
|
||||||
}
|
}
|
||||||
|
|||||||
@ -108,7 +108,12 @@ const resources = {
|
|||||||
'models.add.group_name.placeholder': 'Optional e.g. ChatGPT',
|
'models.add.group_name.placeholder': 'Optional e.g. ChatGPT',
|
||||||
'models.empty': 'No models found',
|
'models.empty': 'No models found',
|
||||||
'assistant.title': 'Default Assistant',
|
'assistant.title': 'Default Assistant',
|
||||||
'about.description': 'A powerful AI assistant for producer'
|
'about.description': 'A powerful AI assistant for producer',
|
||||||
|
'about.updateNotAvailable': 'You are using the latest version',
|
||||||
|
'about.checkingUpdate': 'Checking for updates...',
|
||||||
|
'about.updateError': 'Update error',
|
||||||
|
'about.checkUpdate': 'Check Update',
|
||||||
|
'about.downloading': 'Downloading...'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -217,7 +222,12 @@ const resources = {
|
|||||||
'models.add.group_name.placeholder': '例如 ChatGPT',
|
'models.add.group_name.placeholder': '例如 ChatGPT',
|
||||||
'models.empty': '没有模型',
|
'models.empty': '没有模型',
|
||||||
'assistant.title': '默认助手',
|
'assistant.title': '默认助手',
|
||||||
'about.description': '一个为创造者而生的 AI 助手'
|
'about.description': '一个为创造者而生的 AI 助手',
|
||||||
|
'about.updateNotAvailable': '你的软件已是最新版本',
|
||||||
|
'about.checkingUpdate': '正在检查更新...',
|
||||||
|
'about.updateError': '更新出错',
|
||||||
|
'about.checkUpdate': '检查更新',
|
||||||
|
'about.downloading': '正在下载更新...'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,17 +2,11 @@ import localforage from 'localforage'
|
|||||||
import KeyvStorage from '@kangfenmao/keyv-storage'
|
import KeyvStorage from '@kangfenmao/keyv-storage'
|
||||||
import * as Sentry from '@sentry/electron/renderer'
|
import * as Sentry from '@sentry/electron/renderer'
|
||||||
|
|
||||||
function init() {
|
function initSentry() {
|
||||||
localforage.config({
|
// Disable sentry in development mode
|
||||||
driver: localforage.INDEXEDDB,
|
if (process?.env?.NODE_ENV === 'development') {
|
||||||
name: 'CherryAI',
|
return
|
||||||
version: 1.0,
|
}
|
||||||
storeName: 'cherryai',
|
|
||||||
description: 'Cherry Studio Storage'
|
|
||||||
})
|
|
||||||
|
|
||||||
window.keyv = new KeyvStorage()
|
|
||||||
window.keyv.init()
|
|
||||||
|
|
||||||
Sentry.init({
|
Sentry.init({
|
||||||
integrations: [Sentry.browserTracingIntegration(), Sentry.replayIntegration()],
|
integrations: [Sentry.browserTracingIntegration(), Sentry.replayIntegration()],
|
||||||
@ -29,4 +23,19 @@ function init() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
localforage.config({
|
||||||
|
driver: localforage.INDEXEDDB,
|
||||||
|
name: 'CherryAI',
|
||||||
|
version: 1.0,
|
||||||
|
storeName: 'cherryai',
|
||||||
|
description: 'Cherry Studio Storage'
|
||||||
|
})
|
||||||
|
|
||||||
|
window.keyv = new KeyvStorage()
|
||||||
|
window.keyv.init()
|
||||||
|
|
||||||
|
initSentry()
|
||||||
|
}
|
||||||
|
|
||||||
init()
|
init()
|
||||||
|
|||||||
@ -1,14 +1,34 @@
|
|||||||
import { Avatar } from 'antd'
|
import { Avatar, Button, Progress } from 'antd'
|
||||||
import { FC, useEffect, useState } from 'react'
|
import { FC, useEffect, useState } from 'react'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import Logo from '@renderer/assets/images/logo.png'
|
import Logo from '@renderer/assets/images/logo.png'
|
||||||
import { runAsyncFunction } from '@renderer/utils'
|
import { runAsyncFunction } from '@renderer/utils'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import Changelog from './components/Changelog'
|
import Changelog from './components/Changelog'
|
||||||
|
import { debounce } from 'lodash'
|
||||||
|
import { ProgressInfo } from 'electron-updater'
|
||||||
|
|
||||||
const AboutSettings: FC = () => {
|
const AboutSettings: FC = () => {
|
||||||
const [version, setVersion] = useState('')
|
const [version, setVersion] = useState('')
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
const [percent, setPercent] = useState(0)
|
||||||
|
const [checkUpdateLoading, setCheckUpdateLoading] = useState(false)
|
||||||
|
const [downloading, setDownloading] = useState(false)
|
||||||
|
|
||||||
|
const onCheckUpdate = debounce(
|
||||||
|
async () => {
|
||||||
|
if (checkUpdateLoading || downloading) return
|
||||||
|
setCheckUpdateLoading(true)
|
||||||
|
await window.api.checkForUpdate()
|
||||||
|
setCheckUpdateLoading(false)
|
||||||
|
},
|
||||||
|
2000,
|
||||||
|
{ leading: true, trailing: false }
|
||||||
|
)
|
||||||
|
|
||||||
|
const onOpenWebsite = (suffix = '') => {
|
||||||
|
window.api.openWebsite('https://github.com/kangfenmao/cherry-studio' + suffix)
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
runAsyncFunction(async () => {
|
runAsyncFunction(async () => {
|
||||||
@ -17,20 +37,65 @@ const AboutSettings: FC = () => {
|
|||||||
})
|
})
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const ipcRenderer = window.electron.ipcRenderer
|
||||||
|
const removers = [
|
||||||
|
ipcRenderer.on('update-not-available', () => {
|
||||||
|
setCheckUpdateLoading(false)
|
||||||
|
window.message.success(t('settings.about.updateNotAvailable'))
|
||||||
|
}),
|
||||||
|
ipcRenderer.on('update-available', () => {
|
||||||
|
setCheckUpdateLoading(false)
|
||||||
|
}),
|
||||||
|
ipcRenderer.on('download-update', () => {
|
||||||
|
setCheckUpdateLoading(false)
|
||||||
|
setDownloading(true)
|
||||||
|
}),
|
||||||
|
ipcRenderer.on('download-progress', (_, progress: ProgressInfo) => {
|
||||||
|
setPercent(progress.percent)
|
||||||
|
}),
|
||||||
|
ipcRenderer.on('update-error', (_, error) => {
|
||||||
|
setCheckUpdateLoading(false)
|
||||||
|
setDownloading(false)
|
||||||
|
setPercent(0)
|
||||||
|
window.modal.info({
|
||||||
|
title: t('settings.about.updateError'),
|
||||||
|
content: error?.message || t('settings.about.updateError'),
|
||||||
|
icon: null
|
||||||
|
})
|
||||||
|
})
|
||||||
|
]
|
||||||
|
return () => removers.forEach((remover) => remover())
|
||||||
|
}, [t])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<Avatar src={Logo} size={100} style={{ marginTop: 50, minHeight: 100 }} />
|
<AvatarWrapper onClick={() => onOpenWebsite()}>
|
||||||
|
{percent > 0 && (
|
||||||
|
<ProgressCircle
|
||||||
|
type="circle"
|
||||||
|
size={104}
|
||||||
|
percent={percent}
|
||||||
|
showInfo={false}
|
||||||
|
strokeLinecap="butt"
|
||||||
|
strokeColor="#67ad5b"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<Avatar src={Logo} size={100} style={{ marginTop: 50, minHeight: 100 }} />
|
||||||
|
</AvatarWrapper>
|
||||||
<Title>
|
<Title>
|
||||||
Cherry Studio <Version>(v{version})</Version>
|
Cherry Studio <Version onClick={() => onOpenWebsite('/releases')}>(v{version})</Version>
|
||||||
</Title>
|
</Title>
|
||||||
<Description>{t('settings.about.description')}</Description>
|
<Description>{t('settings.about.description')}</Description>
|
||||||
|
<CheckUpdateButton onClick={onCheckUpdate} loading={checkUpdateLoading}>
|
||||||
|
{downloading ? t('settings.about.downloading') : t('settings.about.checkUpdate')}
|
||||||
|
</CheckUpdateButton>
|
||||||
<Changelog />
|
<Changelog />
|
||||||
</Container>
|
</Container>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const Container = styled.div`
|
const Container = styled.div`
|
||||||
padding: 20px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -38,6 +103,8 @@ const Container = styled.div`
|
|||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
height: calc(100vh - var(--navbar-height));
|
height: calc(100vh - var(--navbar-height));
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
|
padding: 0;
|
||||||
|
padding-bottom: 50px;
|
||||||
`
|
`
|
||||||
|
|
||||||
const Title = styled.div`
|
const Title = styled.div`
|
||||||
@ -52,6 +119,7 @@ const Version = styled.span`
|
|||||||
color: var(--color-text-2);
|
color: var(--color-text-2);
|
||||||
margin: 10px 0;
|
margin: 10px 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
cursor: pointer;
|
||||||
`
|
`
|
||||||
|
|
||||||
const Description = styled.div`
|
const Description = styled.div`
|
||||||
@ -60,4 +128,19 @@ const Description = styled.div`
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const CheckUpdateButton = styled(Button)`
|
||||||
|
margin-top: 10px;
|
||||||
|
`
|
||||||
|
|
||||||
|
const AvatarWrapper = styled.div`
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
`
|
||||||
|
|
||||||
|
const ProgressCircle = styled(Progress)`
|
||||||
|
position: absolute;
|
||||||
|
top: 48px;
|
||||||
|
left: -2px;
|
||||||
|
`
|
||||||
|
|
||||||
export default AboutSettings
|
export default AboutSettings
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import changelogZh from '@renderer/CHANGELOG.zh.md?raw'
|
|||||||
import { FC } from 'react'
|
import { FC } from 'react'
|
||||||
import Markdown from 'react-markdown'
|
import Markdown from 'react-markdown'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import styles from '@renderer/assets/styles/changelog.module.scss'
|
import styles from './changelog.module.scss'
|
||||||
import i18n from '@renderer/i18n'
|
import i18n from '@renderer/i18n'
|
||||||
|
|
||||||
const Changelog: FC = () => {
|
const Changelog: FC = () => {
|
||||||
|
|||||||
@ -69,7 +69,8 @@ $code-color: #f0e7db;
|
|||||||
|
|
||||||
ul,
|
ul,
|
||||||
ol {
|
ol {
|
||||||
padding-left: 30px;
|
padding-left: 20px;
|
||||||
|
list-style: disc;
|
||||||
}
|
}
|
||||||
|
|
||||||
li {
|
li {
|
||||||
Loading…
x
Reference in New Issue
Block a user