Skip to content

Commit

Permalink
feat: check for updates (#17)
Browse files Browse the repository at this point in the history
  • Loading branch information
antonreshetov authored Apr 1, 2024
1 parent 2085611 commit 0cfa665
Show file tree
Hide file tree
Showing 9 changed files with 113 additions and 6 deletions.
Binary file modified bun.lockb
Binary file not shown.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"@iconify-json/solar": "^1.1.9",
"@vueuse/core": "^10.7.2",
"apexcharts": "^3.48.0",
"axios": "^1.6.8",
"chroma-js": "^2.4.2",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.0",
Expand Down
5 changes: 5 additions & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { author } from '../package.json'
import { store } from './services/store'
import { timeFormat } from './renderer/utils'
import { menu } from './menu'
import { checkForUpdates } from './services/updates'

const isDev = process.env.NODE_ENV === 'development'

Expand Down Expand Up @@ -155,3 +156,7 @@ if (process.platform === 'darwin') {
copyright: `${author.name} ©2024-${new Date().getFullYear()}`,
})
}

ipcMain.on('check-for-updates', () => {
checkForUpdates()
})
24 changes: 23 additions & 1 deletion src/menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import os from 'node:os'
import type { BrowserWindow, MenuItemConstructorOptions } from 'electron'
import { Menu, dialog, shell } from 'electron'
import { repository, version } from '../package.json'
import { checkForUpdates } from './services/updates'

const isDev = process.env.NODE_ENV === 'development'
const isMac = process.platform === 'darwin'
Expand Down Expand Up @@ -41,7 +42,28 @@ const appMenuCommon: Record<string, MenuItemConstructorOptions> = {
},
update: {
label: 'Check for Updates...',
click: () => console.warn('Check for Updates...'),
click: async (_, focusedWindow) => {
const newVersion = await checkForUpdates()

if (newVersion) {
const buttonId = dialog.showMessageBoxSync(focusedWindow, {
title: 'Update Available',
message: `Version ${newVersion} is available for download. Your version is ${version}.`,
buttons: ['Go to Download', 'OK'],
defaultId: 0,
cancelId: 1,
})

if (buttonId === 0)
shell.openExternal(`${repository.url}/releases/latest`)
}
else {
dialog.showMessageBox(focusedWindow, {
title: 'No Updates Available',
message: 'You are already using the latest version.',
})
}
},
},
devtools: {
label: 'Toggle Developer Tools',
Expand Down
10 changes: 9 additions & 1 deletion src/preload.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// See the Electron documentation for details on how to use preload scripts:
// https://www.electronjs.org/docs/latest/tutorial/process-model#preload-scripts
import { contextBridge, ipcRenderer } from 'electron'
import { contextBridge, ipcRenderer, shell } from 'electron'
import { repository } from '../package.json'
import { api } from './services/api'
import { store } from './services/store'
import type { AppStore } from './services/store/types'
Expand All @@ -22,4 +23,11 @@ contextBridge.exposeInMainWorld('electron', {
onStart: (callback: () => void) => ipcRenderer.on('start', callback),
onStop: (callback: () => void) => ipcRenderer.on('stop', callback),
},
updates: {
checkForUpdates: () => ipcRenderer.send('check-for-updates'),
downloadUpdate: () =>
shell.openExternal(`${repository.url}/releases/latest`),
onUpdateAvailable: (callback: () => void) =>
ipcRenderer.on('update-available', callback),
},
})
15 changes: 13 additions & 2 deletions src/renderer/components/sidebar/Sidebar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { APP_DEFAULTS } from '~/services/store/constants'
import SolarPlayBold from '~icons/solar/play-bold'
import SolarPauseBold from '~icons/solar/pause-bold'
const { store, tray } = window.electron
const { store, tray, updates } = window.electron
const { lastTask, isStarted, timeFormatted, startStop } = useTasks()
const { addFolder } = useFolders()
Expand All @@ -20,7 +20,7 @@ const sidebarRef = ref<HTMLElement>()
const gutterRef = ref<{ $el: HTMLElement }>()
const scrollRef = ref<PS>()
const { sidebarWidth } = useApp()
const { sidebarWidth, isUpdateAvailable } = useApp()
const { width } = useGutter(
sidebarRef,
gutterRef,
Expand Down Expand Up @@ -88,6 +88,17 @@ tray.onStart(() => {
<FoldersTree @update="onUpdateFolders" />
</PerfectScrollbar>
<div class="px-2">
<div
v-if="isUpdateAvailable"
class="flex justify-center mb-2"
>
<UiButton
variant="ghost-sidebar"
@click="updates.downloadUpdate"
>
Update available
</UiButton>
</div>
<div
v-if="lastTask"
class="flex items-center gap-2 bg-white dark:bg-neutral-700 rounded px-2 py-1 dark:text-white"
Expand Down
20 changes: 18 additions & 2 deletions src/renderer/composables/useApp.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { useCssVar } from '@vueuse/core'
import { watchEffect } from 'vue'
import { ref, watchEffect } from 'vue'

const { store } = window.electron
const { store, updates } = window.electron

const isUpdateAvailable = ref(false)

const sidebarWidth = useCssVar('--sidebar-width')
const tasksWidth = useCssVar('--tasks-width')
Expand All @@ -14,8 +16,22 @@ watchEffect(() => {
tasksWidthOffset.value = `${Number.parseInt(sidebarWidth.value) + Number.parseInt(tasksWidth.value)}px`
})

updates.checkForUpdates()

updates.onUpdateAvailable(() => {
isUpdateAvailable.value = true
})

setInterval(
() => {
updates.checkForUpdates()
},
1000 * 60 * 360,
) // 6 часов

export function useApp() {
return {
isUpdateAvailable,
sidebarWidth,
tasksWidth,
tasksWidthOffset,
Expand Down
39 changes: 39 additions & 0 deletions src/services/updates/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/* eslint-disable node/prefer-global/process */
import axios from 'axios'
import { BrowserWindow } from 'electron'
import { repository, version } from '../../../package.json'

const isDev = process.env.NODE_ENV === 'development'

export async function checkForUpdates() {
if (isDev)
return

try {
const res = await axios.get(`${repository.url}/releases/latest`)

const latest = res.request.socket._httpMessage.path
.split('/')
.pop()
.substring(1)

if (latest !== version) {
BrowserWindow.getFocusedWindow()?.webContents.send('update-available')
return latest
}
}
catch (err) {
console.error(err)
}
}

export async function checkForUpdatesWithInterval() {
checkForUpdates()

setInterval(
() => {
checkForUpdates()
},
1000 * 60 * 360,
) // 6 часов
}
5 changes: 5 additions & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ declare global {
onStart: (callback: () => void) => void
onStop: (callback: () => void) => void
}
updates: {
checkForUpdates: () => void
downloadUpdate: () => void
onUpdateAvailable: (callback: () => void) => void
}
}
}
}

0 comments on commit 0cfa665

Please sign in to comment.