diff --git a/app/assets/iconTemplate.png b/app/assets/iconTemplate.png new file mode 100644 index 00000000..7b088254 Binary files /dev/null and b/app/assets/iconTemplate.png differ diff --git a/app/assets/ollama_outline_icon_16x16Template@2x.png b/app/assets/iconTemplate@2x.png similarity index 100% rename from app/assets/ollama_outline_icon_16x16Template@2x.png rename to app/assets/iconTemplate@2x.png diff --git a/app/assets/iconUpdateTemplate.png b/app/assets/iconUpdateTemplate.png new file mode 100644 index 00000000..fa9d7158 Binary files /dev/null and b/app/assets/iconUpdateTemplate.png differ diff --git a/app/assets/iconUpdateTemplate@2x.png b/app/assets/iconUpdateTemplate@2x.png new file mode 100644 index 00000000..ce14192d Binary files /dev/null and b/app/assets/iconUpdateTemplate@2x.png differ diff --git a/app/assets/ollama_icon_16x16Template.png b/app/assets/ollama_icon_16x16Template.png deleted file mode 100644 index a5f7c08e..00000000 Binary files a/app/assets/ollama_icon_16x16Template.png and /dev/null differ diff --git a/app/assets/ollama_icon_16x16Template@2x.png b/app/assets/ollama_icon_16x16Template@2x.png deleted file mode 100644 index 1a94c9e2..00000000 Binary files a/app/assets/ollama_icon_16x16Template@2x.png and /dev/null differ diff --git a/app/assets/ollama_outline_icon_16x16Template.png b/app/assets/ollama_outline_icon_16x16Template.png deleted file mode 100644 index 04ef6561..00000000 Binary files a/app/assets/ollama_outline_icon_16x16Template.png and /dev/null differ diff --git a/app/forge.config.ts b/app/forge.config.ts index 57e6f6dc..fc7639a8 100644 --- a/app/forge.config.ts +++ b/app/forge.config.ts @@ -19,10 +19,10 @@ const config: ForgeConfig = { icon: './assets/icon.icns', extraResource: [ '../ollama', - path.join(__dirname, './assets/ollama_icon_16x16Template.png'), - path.join(__dirname, './assets/ollama_icon_16x16Template@2x.png'), - path.join(__dirname, './assets/ollama_outline_icon_16x16Template.png'), - path.join(__dirname, './assets/ollama_outline_icon_16x16Template@2x.png'), + path.join(__dirname, './assets/iconTemplate.png'), + path.join(__dirname, './assets/iconTemplate@2x.png'), + path.join(__dirname, './assets/iconUpdateTemplate.png'), + path.join(__dirname, './assets/iconUpdateTemplate@2x.png'), ...(process.platform === 'darwin' ? ['../llama/ggml-metal.metal'] : []), ], ...(process.env.SIGN diff --git a/app/src/index.ts b/app/src/index.ts index f74adc66..9924f5ba 100644 --- a/app/src/index.ts +++ b/app/src/index.ts @@ -1,5 +1,15 @@ import { spawn } from 'child_process' -import { app, autoUpdater, dialog, Tray, Menu, BrowserWindow, nativeTheme } from 'electron' +import { + app, + autoUpdater, + dialog, + Tray, + Menu, + BrowserWindow, + MenuItemConstructorOptions, + nativeTheme, + systemPreferences, +} from 'electron' import Store from 'electron-store' import winston from 'winston' import 'winston-daily-rotate-file' @@ -11,7 +21,7 @@ import { installed } from './install' require('@electron/remote/main').initialize() const store = new Store() -let tray: Tray | null = null + let welcomeWindow: BrowserWindow | null = null declare const MAIN_WINDOW_WEBPACK_ENTRY: string @@ -61,35 +71,42 @@ function firstRunWindow() { } } -function createSystemtray() { - let iconPath = nativeTheme.shouldUseDarkColors - ? path.join(__dirname, '..', '..', 'assets', 'ollama_icon_16x16Template.png') - : path.join(__dirname, '..', '..', 'assets', 'ollama_outline_icon_16x16Template.png') +let tray: Tray | null = null - if (app.isPackaged) { - iconPath = nativeTheme.shouldUseDarkColors - ? path.join(process.resourcesPath, 'ollama_icon_16x16Template.png') - : path.join(process.resourcesPath, 'ollama_outline_icon_16x16Template.png') +function setTray(updateAvailable: boolean) { + const menuItemAvailable: MenuItemConstructorOptions = { + label: 'Restart to update', + click: () => autoUpdater.quitAndInstall(), } - tray = new Tray(iconPath) + const menuItemUpToDate: MenuItemConstructorOptions = { + label: 'Ollama is up to date', + enabled: false, + } - nativeTheme.on('updated', function theThemeHasChanged() { - if (nativeTheme.shouldUseDarkColors) { - app.isPackaged - ? tray.setImage(path.join(process.resourcesPath, 'ollama_icon_16x16Template.png')) - : tray.setImage(path.join(__dirname, '..', '..', 'assets', 'ollama_icon_16x16Template.png')) - } else { - app.isPackaged - ? tray.setImage(path.join(process.resourcesPath, 'ollama_outline_icon_16x16Template.png')) - : tray.setImage(path.join(__dirname, '..', '..', 'assets', 'ollama_outline_icon_16x16Template.png')) - } - }) + const menu = Menu.buildFromTemplate([ + ...(updateAvailable + ? [{ label: 'An update is available', enabled: false }, menuItemAvailable] + : [menuItemUpToDate]), + { type: 'separator' }, + { role: 'quit', label: 'Quit Ollama', accelerator: 'Command+Q' }, + ]) - const contextMenu = Menu.buildFromTemplate([{ role: 'quit', label: 'Quit Ollama', accelerator: 'Command+Q' }]) + const iconPath = app.isPackaged + ? updateAvailable + ? path.join(process.resourcesPath, 'iconUpdateTemplate.png') + : path.join(process.resourcesPath, 'iconTemplate.png') + : updateAvailable + ? path.join(__dirname, '..', '..', 'assets', 'iconUpdateTemplate.png') + : path.join(__dirname, '..', '..', 'assets', 'iconTemplate.png') - tray.setContextMenu(contextMenu) - tray.setToolTip('Ollama') + if (!tray) { + tray = new Tray(iconPath) + } + + tray.setToolTip(updateAvailable ? 'An update is available' : 'Ollama') + tray.setContextMenu(menu) + tray.setImage(iconPath) } if (require('electron-squirrel-startup')) { @@ -128,6 +145,17 @@ if (process.platform === 'darwin') { } app.on('ready', () => { + setTray(false) + + if (app.isPackaged) { + heartbeat() + autoUpdater.checkForUpdates() + setInterval(() => { + heartbeat() + autoUpdater.checkForUpdates() + }, 60 * 60 * 1000) + } + if (process.platform === 'darwin') { if (app.isPackaged) { if (!app.isInApplicationsFolder()) { @@ -163,7 +191,6 @@ app.on('ready', () => { } } - createSystemtray() server() if (store.get('first-time-run') && installed()) { @@ -201,29 +228,10 @@ async function heartbeat() { }) } -if (app.isPackaged) { - heartbeat() - autoUpdater.checkForUpdates() - setInterval(() => { - heartbeat() - autoUpdater.checkForUpdates() - }, 60 * 60 * 1000) -} - autoUpdater.on('error', e => { console.error(`update check failed - ${e.message}`) }) -autoUpdater.on('update-downloaded', (_, releaseNotes, releaseName) => { - dialog - .showMessageBox({ - type: 'info', - buttons: ['Restart Now', 'Later'], - title: 'New update available', - message: process.platform === 'win32' ? releaseNotes : releaseName, - detail: 'A new version of Ollama is available. Restart to apply the update.', - }) - .then(returnValue => { - if (returnValue.response === 0) autoUpdater.quitAndInstall() - }) +autoUpdater.on('update-downloaded', () => { + setTray(true) }) diff --git a/scripts/publish.sh b/scripts/publish.sh index afd2b2ac..63e5ea0c 100755 --- a/scripts/publish.sh +++ b/scripts/publish.sh @@ -17,15 +17,16 @@ npm --prefix app run make:sign # Create a new tag if it doesn't exist. if ! git rev-parse v$VERSION >/dev/null 2>&1; then git tag v$VERSION - git push origin v$VERSION fi +git push origin v$VERSION + mkdir -p dist cp app/out/make/zip/${OS}/${ARCH}/Ollama-${OS}-${ARCH}-${VERSION}.zip dist/Ollama-${OS}-${ARCH}.zip cp ./ollama dist/ollama-${OS}-${ARCH} # Create a new release. -gh release create -p v$VERSION +gh release create -p v$VERSION -t v$VERSION # Upload the zip file. gh release upload v$VERSION ./dist/Ollama-${OS}-${ARCH}.zip