From df37ed8583a2565f2752c4314ff9e35b6a34fb72 Mon Sep 17 00:00:00 2001 From: Murilo Polese Date: Wed, 17 Apr 2024 12:25:58 +0200 Subject: [PATCH 01/17] Initializing variables --- backend/helpers.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/helpers.js b/backend/helpers.js index 427d360..0976293 100644 --- a/backend/helpers.js +++ b/backend/helpers.js @@ -4,12 +4,12 @@ const path = require('path') async function openFolderDialog(win) { // https://stackoverflow.com/questions/46027287/electron-open-folder-dialog - let dir = await dialog.showOpenDialog(win, { properties: [ 'openDirectory' ] }) + const dir = await dialog.showOpenDialog(win, { properties: [ 'openDirectory' ] }) return dir.filePaths[0] || null } function listFolder(folder) { - files = fs.readdirSync(path.resolve(folder)) + let files = fs.readdirSync(path.resolve(folder)) // Filter out directories files = files.filter(f => { let filePath = path.resolve(folder, f) @@ -38,7 +38,7 @@ function ilistFolder(folder) { function getAllFiles(dirPath, arrayOfFiles) { // https://coderrocketfuel.com/article/recursively-list-all-the-files-in-a-directory-using-node-js - files = ilistFolder(dirPath) + let files = ilistFolder(dirPath) arrayOfFiles = arrayOfFiles || [] files.forEach(function(file) { const p = path.join(dirPath, file.path) From ba3241d3ca0c86f34758985ee629307c0c6663d1 Mon Sep 17 00:00:00 2001 From: Murilo Polese Date: Wed, 17 Apr 2024 12:26:37 +0200 Subject: [PATCH 02/17] Electron will wait for UI to confirm close --- backend/ipc.js | 13 ++++++++++++- index.js | 10 ++++++++-- preload.js | 5 ++++- ui/arduino/store.js | 9 +++++++++ 4 files changed, 33 insertions(+), 4 deletions(-) diff --git a/backend/ipc.js b/backend/ipc.js index c97daba..b1133b4 100644 --- a/backend/ipc.js +++ b/backend/ipc.js @@ -6,7 +6,7 @@ const { getAllFiles } = require('./helpers.js') -module.exports = function registerIPCHandlers(win, ipcMain) { +module.exports = function registerIPCHandlers(win, ipcMain, app) { ipcMain.handle('open-folder', async (event) => { console.log('ipcMain', 'open-folder') const folder = await openFolderDialog(win) @@ -107,4 +107,15 @@ module.exports = function registerIPCHandlers(win, ipcMain) { win.setMinimumSize(minWidth, minHeight) }) + + ipcMain.handle('confirm-close', () => { + console.log('ipcMain', 'confirm-close') + app.exit() + }) + + win.on('close', (event) => { + console.log('BrowserWindow', 'close') + event.preventDefault() + win.webContents.send('check-before-close') + }) } diff --git a/index.js b/index.js index 2992967..3f01633 100644 --- a/index.js +++ b/index.js @@ -23,11 +23,17 @@ function createWindow () { // and load the index.html of the app. win.loadFile('ui/arduino/index.html') - registerIPCHandlers(win, ipcMain) + registerIPCHandlers(win, ipcMain, app) registerMenu(win) + + app.on('activate', () => { + if (BrowserWindow.getAllWindows().length === 0) createWindow() + }) + // app.on('window-all-closed', () => { + // if (process.platform !== 'darwin') app.quit() + // }) } // TODO: Loading splash screen - app.whenReady().then(createWindow) diff --git a/preload.js b/preload.js index d7b24e8..cce145f 100644 --- a/preload.js +++ b/preload.js @@ -151,9 +151,12 @@ const Disk = { const Window = { setWindowSize: (minWidth, minHeight) => { ipcRenderer.invoke('set-window-size', minWidth, minHeight) - } + }, + beforeClose: (callback) => ipcRenderer.on('check-before-close', callback), + confirmClose: () => ipcRenderer.invoke('confirm-close') } + contextBridge.exposeInMainWorld('BridgeSerial', Serial) contextBridge.exposeInMainWorld('BridgeDisk', Disk) contextBridge.exposeInMainWorld('BridgeWindow', Window) diff --git a/ui/arduino/store.js b/ui/arduino/store.js index 80656a5..6d965e7 100644 --- a/ui/arduino/store.js +++ b/ui/arduino/store.js @@ -1303,6 +1303,15 @@ async function store(state, emitter) { emitter.emit('render') }) + win.beforeClose(async () => { + const hasChanges = !!state.openFiles.find(f => f.parentFolder && f.hasChanges) + if (hasChanges) { + const response = await confirm('You may have unsaved changes. Are you sure you want to proceed?', 'Yes', 'Cancel') + if (!response) return false + } + await win.confirmClose() + }) + function createFile(args) { const { source, From 8515dd52bc9c28d2a1bb5a78c41a1d39be81cd5a Mon Sep 17 00:00:00 2001 From: Murilo Polese Date: Thu, 18 Apr 2024 12:32:35 +0200 Subject: [PATCH 03/17] Remember scroll position between tabs --- ui/arduino/views/components/elements/editor.js | 18 +++++++++++++++++- ui/arduino/views/components/elements/tab.js | 8 ++++---- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/ui/arduino/views/components/elements/editor.js b/ui/arduino/views/components/elements/editor.js index 81d6fcb..9097936 100644 --- a/ui/arduino/views/components/elements/editor.js +++ b/ui/arduino/views/components/elements/editor.js @@ -3,15 +3,31 @@ class CodeMirrorEditor extends Component { super() this.editor = null this.content = '# empty file' + this.scrollTop = 0 } load(el) { const onCodeChange = (update) => { - // console.log('code change', this.content) this.content = update.state.doc.toString() this.onChange() } this.editor = createEditor(this.content, el, onCodeChange) + this.editor.scrollDOM.addEventListener('scroll', this.updateScrollPosition.bind(this)) + setTimeout(() => { + this.editor.scrollDOM.scrollTo({ + top: this.scrollTop, + left: 0 + }) + }, 1) + } + + updateScrollPosition(e) { + console.log(e.target.scrollTop) + this.scrollTop = e.target.scrollTop + } + + unload() { + this.editor.scrollDOM.removeEventListener('scroll', this.updateScrollPosition) } createElement(content) { diff --git a/ui/arduino/views/components/elements/tab.js b/ui/arduino/views/components/elements/tab.js index f0070f3..6036d6b 100644 --- a/ui/arduino/views/components/elements/tab.js +++ b/ui/arduino/views/components/elements/tab.js @@ -57,7 +57,7 @@ function Tab(args) { } function selectTab(e) { - if(e.target.tagName === 'BUTTON' || e.target.tagName === 'IMG') return + if(e.target.classList.contains('close-tab')) return onSelectTab(e) } @@ -71,9 +71,9 @@ function Tab(args) {
${hasChanges ? '*' : ''} ${text}
-
-
From fef591641750221b9578710b2fdc16e201040551 Mon Sep 17 00:00:00 2001 From: Murilo Polese Date: Thu, 18 Apr 2024 15:09:08 +0200 Subject: [PATCH 04/17] Increase timeout --- .../views/components/elements/editor.js | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/ui/arduino/views/components/elements/editor.js b/ui/arduino/views/components/elements/editor.js index 9097936..4158d4a 100644 --- a/ui/arduino/views/components/elements/editor.js +++ b/ui/arduino/views/components/elements/editor.js @@ -6,37 +6,39 @@ class CodeMirrorEditor extends Component { this.scrollTop = 0 } + createElement(content) { + if (content) this.content = content + return html`
` + } + + load(el) { const onCodeChange = (update) => { this.content = update.state.doc.toString() this.onChange() } this.editor = createEditor(this.content, el, onCodeChange) - this.editor.scrollDOM.addEventListener('scroll', this.updateScrollPosition.bind(this)) + setTimeout(() => { + this.editor.scrollDOM.addEventListener('scroll', this.updateScrollPosition.bind(this)) this.editor.scrollDOM.scrollTo({ top: this.scrollTop, left: 0 }) - }, 1) + }, 10) } - updateScrollPosition(e) { - console.log(e.target.scrollTop) - this.scrollTop = e.target.scrollTop + update() { + return false } unload() { this.editor.scrollDOM.removeEventListener('scroll', this.updateScrollPosition) } - createElement(content) { - if (content) this.content = content - return html`
` - } - - update() { - return false + updateScrollPosition(e) { + console.log(e.target.scrollTop) + this.scrollTop = e.target.scrollTop } onChange() { From b868efee9ef230e73d872ecfe069adfdc0262d2d Mon Sep 17 00:00:00 2001 From: Murilo Polese Date: Thu, 18 Apr 2024 16:13:32 +0200 Subject: [PATCH 05/17] Remove console.log --- ui/arduino/views/components/elements/editor.js | 1 - 1 file changed, 1 deletion(-) diff --git a/ui/arduino/views/components/elements/editor.js b/ui/arduino/views/components/elements/editor.js index 4158d4a..091c6fa 100644 --- a/ui/arduino/views/components/elements/editor.js +++ b/ui/arduino/views/components/elements/editor.js @@ -37,7 +37,6 @@ class CodeMirrorEditor extends Component { } updateScrollPosition(e) { - console.log(e.target.scrollTop) this.scrollTop = e.target.scrollTop } From edfccf80ea75d30596dbe6be1c3c031404235d48 Mon Sep 17 00:00:00 2001 From: ubi de feo Date: Fri, 19 Apr 2024 07:44:30 +0200 Subject: [PATCH 06/17] First Apple Silicon build support. Signed-off-by: ubi de feo --- .github/workflows/build.yml | 3 ++- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 137a1ec..252f774 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -24,7 +24,8 @@ jobs: config: - os: windows-2019 - os: ubuntu-latest - - os: macos-latest + - os: macos-13 + - os: macos-14 runs-on: ${{ matrix.config.os }} timeout-minutes: 90 diff --git a/package-lock.json b/package-lock.json index 61b8548..d2c4e01 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "arduino-lab-micropython-ide", - "version": "0.9.0", + "version": "0.9.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "arduino-lab-micropython-ide", - "version": "0.9.0", + "version": "0.9.1", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index ad5c2cd..74ab24b 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "post-set-shell": "npm config set script-shell bash", "rebuild": "electron-rebuild", "dev": "electron --inspect ./", - "build": "npm run post-set-shell && electron-builder $(if [ $(uname -m) = arm64 ]; then echo --mac --x64; fi)", + "build": "npm run post-set-shell && electron-builder", "postinstall": "npm run post-set-shell && npm run rebuild" }, "devDependencies": { From 87bf0d10dd4c59abec0695759dcc8fad510efeb7 Mon Sep 17 00:00:00 2001 From: ubi de feo Date: Fri, 19 Apr 2024 08:03:35 +0200 Subject: [PATCH 07/17] Workflow: added arm64 to artifacts matrix. Signed-off-by: ubi de feo --- .github/workflows/build.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 252f774..9f35452 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -100,6 +100,8 @@ jobs: name: Arduino-Lab-for-MicroPython_Linux_X86-64 - path: "*-mac_x64.zip" name: Arduino-Lab-for-MicroPython_macOS_X86-64 + - path: "*-mac_arm64.zip" + name: Arduino-Lab-for-MicroPython_macOS_arm-64 # - path: "*Windows_64bit.exe" # name: Windows_X86-64_interactive_installer # - path: "*Windows_64bit.msi" From 83d5d595d1e7815b34f110820f7504bdcae9c925 Mon Sep 17 00:00:00 2001 From: Murilo Polese Date: Mon, 22 Apr 2024 14:07:36 +0200 Subject: [PATCH 08/17] Make a component for overlays --- ui/arduino/index.html | 1 + ui/arduino/main.js | 31 +++++++++++++------------- ui/arduino/views/components/overlay.js | 16 +++++++++++++ 3 files changed, 32 insertions(+), 16 deletions(-) create mode 100644 ui/arduino/views/components/overlay.js diff --git a/ui/arduino/index.html b/ui/arduino/index.html index 25f1967..8478cc7 100644 --- a/ui/arduino/index.html +++ b/ui/arduino/index.html @@ -30,6 +30,7 @@ + diff --git a/ui/arduino/main.js b/ui/arduino/main.js index f7d1ef7..c5e68e5 100644 --- a/ui/arduino/main.js +++ b/ui/arduino/main.js @@ -19,27 +19,26 @@ function App(state, emit) { ` } - let overlay = html`
` - - if (state.diskFiles == null) { - emit('load-disk-files') - overlay = html`

Loading files...

` + if (state.view == 'file-manager') { + return html` +
+ ${FileManagerView(state, emit)} + ${Overlay(state, emit)} +
+ ` + } else { + return html` +
+ ${EditorView(state, emit)} + ${Overlay(state, emit)} +
+ ` } - - if (state.isRemoving) overlay = html`

Removing...

` - if (state.isConnecting) overlay = html`

Connecting...

` - if (state.isLoadingFiles) overlay = html`

Loading files...

` - if (state.isSaving) overlay = html`

Saving file... ${state.savingProgress}

` - if (state.isTransferring) overlay = html`

Transferring file... ${state.transferringProgress}

` - - const view = state.view == 'editor' ? EditorView(state, emit) : FileManagerView(state, emit) return html`
- ${view} - ${overlay} + ${Overlay(state, emit)}
` - } window.addEventListener('load', () => { diff --git a/ui/arduino/views/components/overlay.js b/ui/arduino/views/components/overlay.js new file mode 100644 index 0000000..1b9389c --- /dev/null +++ b/ui/arduino/views/components/overlay.js @@ -0,0 +1,16 @@ +function Overlay(state, emit) { + let overlay = html`
` + + if (state.diskFiles == null) { + emit('load-disk-files') + overlay = html`

Loading files...

` + } + + if (state.isRemoving) overlay = html`

Removing...

` + if (state.isConnecting) overlay = html`

Connecting...

` + if (state.isLoadingFiles) overlay = html`

Loading files...

` + if (state.isSaving) overlay = html`

Saving file... ${state.savingProgress}

` + if (state.isTransferring) overlay = html`

Transferring file... ${state.transferringProgress}

` + + return overlay +} From 51430789fb87265627772181c824d1ee70fe9639 Mon Sep 17 00:00:00 2001 From: Murilo Polese Date: Mon, 22 Apr 2024 14:08:13 +0200 Subject: [PATCH 09/17] No need to use `await` here --- preload.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/preload.js b/preload.js index cce145f..05abf0c 100644 --- a/preload.js +++ b/preload.js @@ -13,10 +13,10 @@ const Serial = { return ports.filter(p => p.vendorId && p.productId) }, connect: async (path) => { - return await board.open(path) + return board.open(path) }, disconnect: async () => { - return await board.close() + return board.close() }, run: async (code) => { return board.run(code) From ec733cabcaf45640fff0c844995f354b0c35a7b6 Mon Sep 17 00:00:00 2001 From: Murilo Polese Date: Mon, 22 Apr 2024 14:08:42 +0200 Subject: [PATCH 10/17] Check if there is a `diskNavigationRoot` before refreshing files --- ui/arduino/main.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ui/arduino/main.js b/ui/arduino/main.js index c5e68e5..bf693df 100644 --- a/ui/arduino/main.js +++ b/ui/arduino/main.js @@ -48,7 +48,9 @@ window.addEventListener('load', () => { app.mount('#app') app.emitter.on('DOMContentLoaded', () => { - app.emitter.emit('refresh-files') + if (app.state.diskNavigationRoot) { + app.emitter.emit('refresh-files') + } }) }) From c13304ab21eff0beb2fe0940778c56718c55f2d6 Mon Sep 17 00:00:00 2001 From: Murilo Polese Date: Tue, 23 Apr 2024 09:26:57 +0200 Subject: [PATCH 11/17] Enable devtools on production --- backend/menu.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/backend/menu.js b/backend/menu.js index 3ee40a6..6b62cdf 100644 --- a/backend/menu.js +++ b/backend/menu.js @@ -4,7 +4,6 @@ const openAboutWindow = require('about-window').default module.exports = function registerMenu(win) { const isMac = process.platform === 'darwin' - const isDev = !app.isPackaged const template = [ ...(isMac ? [{ label: app.name, @@ -56,17 +55,13 @@ module.exports = function registerMenu(win) { label: 'View', submenu: [ { role: 'reload' }, + { role: 'toggleDevTools' }, { type: 'separator' }, { role: 'resetZoom' }, { role: 'zoomIn' }, { role: 'zoomOut' }, { type: 'separator' }, { role: 'togglefullscreen' }, - ...(isDev ? [ - { type: 'separator' }, - { role: 'toggleDevTools' }, - ]:[ - ]) ] }, { From 3c3eecc8478747e3cb632021ed80d3415d9adb0d Mon Sep 17 00:00:00 2001 From: Murilo Polese Date: Tue, 23 Apr 2024 10:41:48 +0200 Subject: [PATCH 12/17] Splash screen --- index.js | 30 +++++++++++++++++++++++------- ui/arduino/splash.html | 21 +++++++++++++++++++++ 2 files changed, 44 insertions(+), 7 deletions(-) create mode 100644 ui/arduino/splash.html diff --git a/index.js b/index.js index 3f01633..e2130c6 100644 --- a/index.js +++ b/index.js @@ -6,6 +6,8 @@ const registerIPCHandlers = require('./backend/ipc.js') const registerMenu = require('./backend/menu.js') let win = null // main window +let splash = null +let splashTimeout = null // START APP function createWindow () { @@ -17,11 +19,30 @@ function createWindow () { nodeIntegration: false, webSecurity: true, enableRemoteModule: false, - preload: path.join(__dirname, "preload.js") + preload: path.join(__dirname, "preload.js"), + show: false } }) // and load the index.html of the app. win.loadFile('ui/arduino/index.html') + // If the app takes a while to open, show splash screen + splashTimeout = setTimeout(() => { + // Create the splash screen + splash = new BrowserWindow({ + width: 560, + height: 180, + transparent: true, + frame: false, + alwaysOnTop: true + }); + splash.loadFile('ui/arduino/splash.html') + }, 250) + + win.once('ready-to-show', () => { + clearTimeout(splashTimeout) + if (splash) splash.destroy() + win.show() + }) registerIPCHandlers(win, ipcMain, app) registerMenu(win) @@ -29,11 +50,6 @@ function createWindow () { app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) createWindow() }) - // app.on('window-all-closed', () => { - // if (process.platform !== 'darwin') app.quit() - // }) } - -// TODO: Loading splash screen -app.whenReady().then(createWindow) +app.on('ready', createWindow) diff --git a/ui/arduino/splash.html b/ui/arduino/splash.html new file mode 100644 index 0000000..6d7e2e1 --- /dev/null +++ b/ui/arduino/splash.html @@ -0,0 +1,21 @@ + + + + + Arduino Lab for MicroPython + + + + Arduino Lab For MicroPython Logo + + From 4aadc2935fd9500aae826e38652da32021d420fa Mon Sep 17 00:00:00 2001 From: Murilo Polese Date: Tue, 23 Apr 2024 11:40:43 +0200 Subject: [PATCH 13/17] Encoding image as base64 to load faster --- ui/arduino/splash.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/arduino/splash.html b/ui/arduino/splash.html index 6d7e2e1..15ae0b4 100644 --- a/ui/arduino/splash.html +++ b/ui/arduino/splash.html @@ -16,6 +16,6 @@ - Arduino Lab For MicroPython Logo + Arduino Lab For MicroPython Logo From 2b36cfabf2552dcb7dc416943740e0c06bfb6703 Mon Sep 17 00:00:00 2001 From: Murilo Polese Date: Tue, 23 Apr 2024 11:44:30 +0200 Subject: [PATCH 14/17] Always show the splash screen for a brief time --- index.js | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/index.js b/index.js index e2130c6..b38f989 100644 --- a/index.js +++ b/index.js @@ -7,7 +7,7 @@ const registerMenu = require('./backend/menu.js') let win = null // main window let splash = null -let splashTimeout = null +let splashTimestamp = null // START APP function createWindow () { @@ -25,22 +25,27 @@ function createWindow () { }) // and load the index.html of the app. win.loadFile('ui/arduino/index.html') + // If the app takes a while to open, show splash screen - splashTimeout = setTimeout(() => { - // Create the splash screen - splash = new BrowserWindow({ - width: 560, - height: 180, - transparent: true, - frame: false, - alwaysOnTop: true - }); - splash.loadFile('ui/arduino/splash.html') - }, 250) + // Create the splash screen + splash = new BrowserWindow({ + width: 450, + height: 140, + transparent: true, + frame: false, + alwaysOnTop: true + }); + splash.loadFile('ui/arduino/splash.html') + splashTimestamp = Date.now() win.once('ready-to-show', () => { - clearTimeout(splashTimeout) - if (splash) splash.destroy() + if (Date.now()-splashTimestamp > 1000) { + splash.destroy() + } else { + setTimeout(() => { + splash.destroy() + }, 500) + } win.show() }) From 36b169a103cc457a6012586f030fabf8a05c8688 Mon Sep 17 00:00:00 2001 From: Murilo Polese Date: Tue, 23 Apr 2024 17:30:35 +0200 Subject: [PATCH 15/17] Switch to tab if file is already open --- ui/arduino/store.js | 139 +++++++++++++++++++++----------------------- 1 file changed, 67 insertions(+), 72 deletions(-) diff --git a/ui/arduino/store.js b/ui/arduino/store.js index 6d965e7..93ed063 100644 --- a/ui/arduino/store.js +++ b/ui/arduino/store.js @@ -1021,17 +1021,19 @@ async function store(state, emitter) { emitter.on('toggle-file-selection', (file, source, event) => { log('toggle-file-selection', file, source, event) + let parentFolder = source == 'board' ? state.boardNavigationPath : state.diskNavigationPath // Single file selection unless holding keyboard key if (event && !event.ctrlKey && !event.metaKey) { state.selectedFiles = [{ fileName: file.fileName, type: file.type, source: source, - parentFolder: file.parentFolder + parentFolder: parentFolder }] emitter.emit('render') return } + const isSelected = state.selectedFiles.find((f) => { return f.fileName === file.fileName && f.source === source }) @@ -1044,80 +1046,90 @@ async function store(state, emitter) { fileName: file.fileName, type: file.type, source: source, - parentFolder: file.parentFolder + parentFolder: parentFolder }) } emitter.emit('render') }) emitter.on('open-selected-files', async () => { log('open-selected-files') - let files = [] + let filesToOpen = [] + let filesAlreadyOpen = [] for (let i in state.selectedFiles) { let selectedFile = state.selectedFiles[i] - let openFile = null if (selectedFile.type == 'folder') { // Don't open folders continue } - if (selectedFile.source == 'board') { - const fileContent = await serial.loadFile( - serial.getFullPath( - '/', - state.boardNavigationPath, - selectedFile.fileName + // ALl good until here + + const alreadyOpen = state.openFiles.find((f) => { + return f.fileName == selectedFile.fileName + && f.source == selectedFile.source + && f.parentFolder == selectedFile.parentFolder + }) + console.log('already open', alreadyOpen) + + if (!alreadyOpen) { + // This file is not open yet, + // load content and append it to the list of files to open + let file = null + if (selectedFile.source == 'board') { + const fileContent = await serial.loadFile( + serial.getFullPath( + state.boardNavigationRoot, + state.boardNavigationPath, + selectedFile.fileName + ) ) - ) - openFile = createFile({ - parentFolder: state.boardNavigationPath, - fileName: selectedFile.fileName, - source: selectedFile.source, - content: fileContent - }) - openFile.editor.onChange = function() { - openFile.hasChanges = true - emitter.emit('render') - } - } else if (selectedFile.source == 'disk') { - const fileContent = await disk.loadFile( - disk.getFullPath( - state.diskNavigationRoot, - state.diskNavigationPath, - selectedFile.fileName + file = createFile({ + parentFolder: state.boardNavigationPath, + fileName: selectedFile.fileName, + source: selectedFile.source, + content: fileContent + }) + file.editor.onChange = function() { + file.hasChanges = true + emitter.emit('render') + } + } else if (selectedFile.source == 'disk') { + const fileContent = await disk.loadFile( + disk.getFullPath( + state.diskNavigationRoot, + state.diskNavigationPath, + selectedFile.fileName + ) ) - ) - openFile = createFile({ - parentFolder: state.diskNavigationPath, - fileName: selectedFile.fileName, - source: selectedFile.source, - content: fileContent - }) - openFile.editor.onChange = function() { - openFile.hasChanges = true - emitter.emit('render') + file = createFile({ + parentFolder: state.diskNavigationPath, + fileName: selectedFile.fileName, + source: selectedFile.source, + content: fileContent + }) + file.editor.onChange = function() { + file.hasChanges = true + emitter.emit('render') + } } + filesToOpen.push(file) + } else { + // This file is already open, + // append it to the list of files that are already open + filesAlreadyOpen.push(alreadyOpen) } - files.push(openFile) } - files = files.filter((f) => { // find files to open - let isAlready = false - state.openFiles.forEach((g) => { // check if file is already open - if ( - g.fileName == f.fileName - && g.source == f.source - && g.parentFolder == f.parentFolder - ) { - isAlready = true - } - }) - return !isAlready - }) - - if (files.length > 0) { - state.openFiles = state.openFiles.concat(files) - state.editingFile = files[0].id + // If opening an already open file, switch to its tab + if (filesAlreadyOpen.length > 0) { + state.editingFile = filesAlreadyOpen[0].id + } + // If there are new files to open, they take priority + if (filesToOpen.length > 0) { + state.editingFile = filesToOpen[0].id } + state.openFiles = state.openFiles.concat(filesToOpen) + state.view = 'editor' emitter.emit('render') }) @@ -1476,23 +1488,6 @@ function canEdit({ selectedFiles }) { return files.length != 0 } -function toggleFileSelection({ fileName, source, selectedFiles }) { - let result = [] - let file = selectedFiles.find((f) => { - return f.fileName === fileName && f.source === source - }) - if (file) { - // filter file out - result = selectedFiles.filter((f) => { - return f.fileName !== fileName && f.source !== source - }) - } else { - // push file - selectedFiles.push({ fileName, source }) - } - return result -} - async function removeBoardFolder(fullPath) { // TODO: Replace with getting the file tree from the board and deleting one by one let output = await serial.execFile('./ui/arduino/helpers.py') From 8b085dc332e0ccdee60e18f92906100034a7a96f Mon Sep 17 00:00:00 2001 From: Murilo Polese Date: Thu, 25 Apr 2024 10:46:30 +0200 Subject: [PATCH 16/17] Include helper as extra resource and load its path correctly --- backend/ipc.js | 9 +++++++++ package.json | 1 + preload.js | 6 +++++- ui/arduino/store.js | 21 +++++++++++++++++++-- 4 files changed, 34 insertions(+), 3 deletions(-) diff --git a/backend/ipc.js b/backend/ipc.js index b1133b4..d4ddc74 100644 --- a/backend/ipc.js +++ b/backend/ipc.js @@ -113,6 +113,15 @@ module.exports = function registerIPCHandlers(win, ipcMain, app) { app.exit() }) + ipcMain.handle('is-packaged', () => { + return app.isPackaged + }) + + ipcMain.handle('get-app-path', () => { + console.log('ipcMain', 'get-app-path') + return app.getAppPath() + }) + win.on('close', (event) => { console.log('BrowserWindow', 'close') event.preventDefault() diff --git a/package.json b/package.json index 74ab24b..d87247b 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "build": { "appId": "cc.arduino.micropython-lab", "artifactName": "${productName}-${os}_${arch}.${ext}", + "extraResources": "./ui/arduino/helpers.py", "mac": { "target": "zip", "icon": "build_resources/icon.icns" diff --git a/preload.js b/preload.js index 05abf0c..3388904 100644 --- a/preload.js +++ b/preload.js @@ -145,6 +145,9 @@ const Disk = { }, fileExists: async (filePath) => { return ipcRenderer.invoke('file-exists', filePath) + }, + getAppPath: () => { + return ipcRenderer.invoke('get-app-path') } } @@ -153,7 +156,8 @@ const Window = { ipcRenderer.invoke('set-window-size', minWidth, minHeight) }, beforeClose: (callback) => ipcRenderer.on('check-before-close', callback), - confirmClose: () => ipcRenderer.invoke('confirm-close') + confirmClose: () => ipcRenderer.invoke('confirm-close'), + isPackaged: () => ipcRenderer.invoke('is-packaged') } diff --git a/ui/arduino/store.js b/ui/arduino/store.js index 93ed063..f008c4b 100644 --- a/ui/arduino/store.js +++ b/ui/arduino/store.js @@ -1490,7 +1490,7 @@ function canEdit({ selectedFiles }) { async function removeBoardFolder(fullPath) { // TODO: Replace with getting the file tree from the board and deleting one by one - let output = await serial.execFile('./ui/arduino/helpers.py') + let output = await serial.execFile(await getHelperFullPath()) await serial.run(`delete_folder('${fullPath}')`) } @@ -1522,7 +1522,7 @@ async function uploadFolder(srcPath, destPath, dataConsumer) { async function downloadFolder(srcPath, destPath, dataConsumer) { dataConsumer = dataConsumer || function() {} await disk.createFolder(destPath) - let output = await serial.execFile('./ui/arduino/helpers.py') + let output = await serial.execFile(await getHelperFullPath()) output = await serial.run(`ilist_all('${srcPath}')`) let files = [] try { @@ -1550,3 +1550,20 @@ async function downloadFolder(srcPath, destPath, dataConsumer) { } } } + +async function getHelperFullPath() { + const appPath = await disk.getAppPath() + if (await win.isPackaged()) { + return disk.getFullPath( + appPath, + '..', + 'ui/arduino/helpers.py' + ) + } else { + return disk.getFullPath( + appPath, + 'ui/arduino/helpers.py', + '' + ) + } +} From caef18f8334390bac97269ec6fb83e6491ef09a6 Mon Sep 17 00:00:00 2001 From: Murilo Polese Date: Mon, 29 Apr 2024 08:39:00 +0200 Subject: [PATCH 17/17] Bump version --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index d2c4e01..883d73e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "arduino-lab-micropython-ide", - "version": "0.9.1", + "version": "0.10.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "arduino-lab-micropython-ide", - "version": "0.9.1", + "version": "0.10.0", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index d87247b..2d3f773 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "arduino-lab-micropython-ide", "productName": "Arduino Lab for MicroPython", - "version": "0.9.1", + "version": "0.10.0", "description": "Arduino Lab for MicroPython is a project sponsored by Arduino, based on original work by Murilo Polese.\nThis is an experimental pre-release software, please direct any questions exclusively to Github issues.", "main": "index.js", "scripts": {