main.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. const { app, BrowserWindow, Menu, shell, dialog } = require('electron');
  2. const path = require('path');
  3. // Graceful auto-updater loading
  4. let autoUpdater = null;
  5. try {
  6. autoUpdater = require('electron-updater').autoUpdater;
  7. console.log('Auto-updater loaded successfully');
  8. } catch (error) {
  9. console.log('Auto-updater not available:', error.message);
  10. }
  11. // Keep a global reference of the window object
  12. let mainWindow;
  13. function createWindow() {
  14. // Create the browser window
  15. mainWindow = new BrowserWindow({
  16. width: 1200,
  17. height: 800,
  18. minWidth: 800,
  19. minHeight: 600,
  20. icon: path.join(__dirname, 'img/logo.png'),
  21. webPreferences: {
  22. nodeIntegration: false,
  23. contextIsolation: true,
  24. enableRemoteModule: false,
  25. webSecurity: true
  26. },
  27. show: false // Don't show until ready
  28. });
  29. // Load the home page
  30. mainWindow.loadFile(path.join(__dirname, 'home.html'));
  31. // Show window when ready to prevent visual flash
  32. mainWindow.once('ready-to-show', () => {
  33. mainWindow.show();
  34. });
  35. // Handle external links
  36. mainWindow.webContents.setWindowOpenHandler(({ url }) => {
  37. shell.openExternal(url);
  38. return { action: 'deny' };
  39. });
  40. // Emitted when the window is closed
  41. mainWindow.on('closed', () => {
  42. mainWindow = null;
  43. });
  44. // Create application menu
  45. createMenu();
  46. }
  47. function createMenu() {
  48. const template = [
  49. {
  50. label: 'File',
  51. submenu: [
  52. {
  53. label: 'New Note',
  54. accelerator: 'CmdOrCtrl+N',
  55. click: () => {
  56. mainWindow.loadFile(path.join(__dirname, 'index.html'));
  57. }
  58. },
  59. {
  60. label: 'Home',
  61. accelerator: 'CmdOrCtrl+H',
  62. click: () => {
  63. mainWindow.loadFile(path.join(__dirname, 'home.html'));
  64. }
  65. },
  66. { type: 'separator' },
  67. {
  68. label: 'Check for Updates',
  69. click: () => {
  70. if (autoUpdater) {
  71. autoUpdater.checkForUpdatesAndNotify();
  72. } else {
  73. dialog.showMessageBox(mainWindow, {
  74. type: 'info',
  75. title: 'Auto-updater Not Available',
  76. message: 'Automatic updates are not available in this build.',
  77. detail: 'Please check for updates manually at: https://github.com/lhamacorp/knotes/releases',
  78. buttons: ['OK']
  79. });
  80. }
  81. }
  82. },
  83. { type: 'separator' },
  84. {
  85. label: 'Quit',
  86. accelerator: process.platform === 'darwin' ? 'Cmd+Q' : 'Ctrl+Q',
  87. click: () => {
  88. app.quit();
  89. }
  90. }
  91. ]
  92. },
  93. {
  94. label: 'Edit',
  95. submenu: [
  96. { role: 'undo' },
  97. { role: 'redo' },
  98. { type: 'separator' },
  99. { role: 'cut' },
  100. { role: 'copy' },
  101. { role: 'paste' },
  102. { role: 'selectall' }
  103. ]
  104. },
  105. {
  106. label: 'View',
  107. submenu: [
  108. { role: 'reload' },
  109. { role: 'forceReload' },
  110. { role: 'toggleDevTools' },
  111. { type: 'separator' },
  112. { role: 'resetZoom' },
  113. { role: 'zoomIn' },
  114. { role: 'zoomOut' },
  115. { type: 'separator' },
  116. { role: 'togglefullscreen' }
  117. ]
  118. },
  119. {
  120. label: 'Window',
  121. submenu: [
  122. { role: 'minimize' },
  123. { role: 'close' }
  124. ]
  125. }
  126. ];
  127. // macOS specific menu adjustments
  128. if (process.platform === 'darwin') {
  129. template.unshift({
  130. label: app.getName(),
  131. submenu: [
  132. { role: 'about' },
  133. { type: 'separator' },
  134. { role: 'services' },
  135. { type: 'separator' },
  136. { role: 'hide' },
  137. { role: 'hideothers' },
  138. { role: 'unhide' },
  139. { type: 'separator' },
  140. { role: 'quit' }
  141. ]
  142. });
  143. // Window menu
  144. template[4].submenu = [
  145. { role: 'close' },
  146. { role: 'minimize' },
  147. { role: 'zoom' },
  148. { type: 'separator' },
  149. { role: 'front' }
  150. ];
  151. }
  152. const menu = Menu.buildFromTemplate(template);
  153. Menu.setApplicationMenu(menu);
  154. }
  155. // Auto-updater configuration
  156. function setupAutoUpdater() {
  157. // Skip if auto-updater is not available
  158. if (!autoUpdater) {
  159. console.log('Auto-updater not available, skipping setup');
  160. return;
  161. }
  162. // Configure auto-updater
  163. autoUpdater.checkForUpdatesAndNotify();
  164. // Auto-updater events
  165. autoUpdater.on('checking-for-update', () => {
  166. console.log('Checking for update...');
  167. });
  168. autoUpdater.on('update-available', (info) => {
  169. console.log('Update available:', info);
  170. dialog.showMessageBox(mainWindow, {
  171. type: 'info',
  172. title: 'Update Available',
  173. message: 'A new version is available. It will be downloaded in the background.',
  174. detail: `Version ${info.version} is now available. The update will be downloaded and installed automatically.`,
  175. buttons: ['OK']
  176. });
  177. });
  178. autoUpdater.on('update-not-available', (info) => {
  179. console.log('Update not available:', info);
  180. });
  181. autoUpdater.on('error', (err) => {
  182. console.error('Error in auto-updater:', err);
  183. });
  184. autoUpdater.on('download-progress', (progressObj) => {
  185. let log_message = "Download speed: " + progressObj.bytesPerSecond;
  186. log_message = log_message + ' - Downloaded ' + progressObj.percent + '%';
  187. log_message = log_message + ' (' + progressObj.transferred + "/" + progressObj.total + ')';
  188. console.log(log_message);
  189. });
  190. autoUpdater.on('update-downloaded', (info) => {
  191. console.log('Update downloaded:', info);
  192. dialog.showMessageBox(mainWindow, {
  193. type: 'info',
  194. title: 'Update Ready',
  195. message: 'Update downloaded and ready to install',
  196. detail: 'The application will restart to apply the update.',
  197. buttons: ['Restart Now', 'Later']
  198. }).then((result) => {
  199. if (result.response === 0) {
  200. autoUpdater.quitAndInstall();
  201. }
  202. });
  203. });
  204. }
  205. // This method will be called when Electron has finished initialization
  206. app.whenReady().then(() => {
  207. createWindow();
  208. // Set up auto-updater after window is created
  209. setTimeout(() => {
  210. setupAutoUpdater();
  211. }, 3000); // Wait 3 seconds after app start
  212. app.on('activate', () => {
  213. // On macOS, re-create a window when the dock icon is clicked
  214. if (BrowserWindow.getAllWindows().length === 0) {
  215. createWindow();
  216. }
  217. });
  218. });
  219. // Quit when all windows are closed
  220. app.on('window-all-closed', () => {
  221. // On macOS, keep the app running even when all windows are closed
  222. if (process.platform !== 'darwin') {
  223. app.quit();
  224. }
  225. });
  226. // Security: Prevent new window creation
  227. app.on('web-contents-created', (event, contents) => {
  228. contents.on('new-window', (event, url) => {
  229. event.preventDefault();
  230. shell.openExternal(url);
  231. });
  232. });