I created an app (done for OSX) that will send a message even when the main window is hidden, currently my main.js is like this:
const { app, shell, BrowserWindow, dialog } = require('electron')
const path = require('path')
const electron = require('electron')
// Enable live reload for all the files inside your project directory
require('electron-reload')(__dirname);
let win = null
function createWindow () {
win = new BrowserWindow({
width: 420,
height: 420,
resizable: false,
fullscreenable: false,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
nodeIntegration: true
}
})
win.on('close', (event) => {
if (app.quitting) {
win = null
} else {
event.preventDefault()
win.hide()
}
})
win.loadFile('index.html')
win.webContents.on('new-window', function(e, url) {
// make sure local urls stay in electron perimeter
if('file://' === url.substr(0, 'file://'.length)) {
return;
}
// and open every other protocols on the browser
e.preventDefault();
shell.openExternal(url);
});
}
app.whenReady().then(() => {
createWindow()
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
})
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => { win.show() })
app.on('before-quit', () => app.quitting = true)
The idea is that when the user try to close the app it will just hide it. I'll need to add something that at certain hours of the day the app will launch the main window again.
Is there a way to make the main window be reopened or to run a code in the background so at certain time of the day the window will be unhidden?
Sure....this will reopen your minimized window
if (win) {
if (win.isMinimized()) win.restore()
win.focus()
}
Related
I am attempting to open a deep link example://example.com in electron, It works perfectly when the aplication is already running however it does not seam to pass the link if it is not. opening the pre-defined variable
deeplinkingUrl
instead
My whole attempt is as follows
const { app, BrowserWindow } = require('electron')
// Module with utilities for working with file and directory paths.
const path = require('path')
// Module with utilities for URL resolution and parsing.
const url = require('url')
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow
// Deep linked url
let deeplinkingUrl = "https://example.com/"
const gotTheLock = app.requestSingleInstanceLock()
// Force Single Instance Application
if (!gotTheLock) {
app.quit()
} else {
app.on('second-instance', (event, argv, cwd) => {
if (process.platform == 'win32') {
deeplinkingUrl = argv.slice(1)
deeplinkingUrl = deeplinkingUrl[1]
deeplinkingUrl = deeplinkingUrl.replace("exmaple", "https")
}
logEverywhere("#app", deeplinkingUrl)
mainWindow.loadURL(deeplinkingUrl)
if (mainWindow) {
if (mainWindow.isMinimized()) mainWindow.restore()
mainWindow.focus()
}
})
}
function createWindow() {
// Create the browser window.
mainWindow = new BrowserWindow({ width: 800, height: 600, icon: __dirname + '/icon.png', })
mainWindow.loadURL(deeplinkingUrl)
mainWindow.webContents.openDevTools()
if (process.platform == 'win32') {
// deeplinkingUrl = process.argv.slice(1)
// deeplinkingUrl = deeplinkingUrl[1]
// deeplinkingUrl = deeplinkingUrl.replace("exmaple", "https")
}
logEverywhere("#newWindow", deeplinkingUrl)
mainWindow.loadURL(deeplinkingUrl)
mainWindow.webContents.openDevTools()
logEverywhere("#argv", process.argv)
// Emitted when the window is closed.
mainWindow.on('closed', function () {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null
})
}
app.on('ready', createWindow)
// Quit when all windows are closed.
app.on('window-all-closed', function () {
// On OS X it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', function () {
// On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow()
}
})
// Define custom protocol handler. Deep linking works on packaged versions of the application!
app.setAsDefaultProtocolClient('exmaple')
// Protocol handler for osx
app.on('open-url', function (event, url) {
event.preventDefault()
deeplinkingUrl = url
logEverywhere("#app", "open-url# " + deeplinkingUrl)
})
// Log both at dev console and at running node console instance
function logEverywhere(s) {
console.log(s)
if (mainWindow && mainWindow.webContents) {
mainWindow.webContents.executeJavaScript(`console.log("${s}")`)
}
}
I am not sure where to go off from here.
App is bubilt using
"electron-builder": "^23.6.0"
and running
"electron": "^21.3.1",
I am running on Win 10
[nativescript] How do I keep a native script - angular app running in the background in IOS. I have a button that opens the in-app browser and there I have a webpage that plays music, I'd like the music to carry on playing when the user leaves the application.
here is my component.ts
export class BrowseComponent implements OnInit {
openLink = async () => {
try {
const url = ''
if (await InAppBrowser.isAvailable()) {
const result = await InAppBrowser.open(url, {
// iOS Properties
dismissButtonStyle: 'done',
preferredBarTintColor: '#3e00be',
preferredControlTintColor: 'white',
readerMode: false,
animated: true,
modalPresentationStyle: 'fullScreen',
modalTransitionStyle: 'crossDissolve',
modalEnabled: true,
enableBarCollapsing: false,
// Android Properties
showTitle: true,
toolbarColor: '#3e00be',
secondaryToolbarColor: 'white',
enableUrlBarHiding: true,
enableDefaultShare: true,
forceCloseOnRedirection: false,
// Specify full animation resource identifier(package:anim/name)
// or only resource name(in case of animation bundled with app).
animations: {
startEnter: 'slide_in_right',
startExit: 'slide_out_left',
endEnter: 'slide_in_left',
endExit: 'slide_out_right'
},
headers: {
'my-custom-header': 'my custom header value'
}
})
// alert({
// title: 'Response',
// message: JSON.stringify(result),
// okButtonText: 'Ok'
// })
}
else {
MyDelegate.prototype.applicationDidEnterBackground = function (application: UIApplication) {
console.log('App is running in background');openUrl(url);
AVAudioSession.sharedInstance().setCategoryWithOptionsError(
AVAudioSessionCategoryPlayAndRecord,
AVAudioSessionCategoryOptions.DefaultToSpeaker
);
};
}
}
catch(error) {
// alert({
// title: 'Error',
// message: error.message,
// okButtonText: 'Ok'
// })
}
}
}
Is it possible to detect in electron if window is already created and close before creating another one?
here is my sample code
// video window listener
ipcMain.on("load-video-window", (event, data) => {
// create the window
//window.close() if window exist;
let videoPlayer = new BrowserWindow({
show: true,
width: 840,
height: 622,
webPreferences: {
nodeIntegration: true,
plugins: true,
},
});
if (process.env.WEBPACK_DEV_SERVER_URL) {
// Load the url of the dev server if in development mode
videoPlayer.loadURL(
process.env.WEBPACK_DEV_SERVER_URL + "video_player.html"
);
if (!process.env.IS_TEST) videoPlayer.webContents.openDevTools();
} else {
videoPlayer.loadURL(`app://./video_player`);
}
videoPlayer.on("closed", () => {
videoPlayer = null;
});
// here we can send the data to the new window
videoPlayer.webContents.on("did-finish-load", () => {
videoPlayer.webContents.send("data", data);
});
});
I think this should work
let playerWindow;
ipcMain.on("load-video-window", (event, data) => {
if (playerWindow) {
playerWindow.close();
}
playerWindow = new BrowserWindow();
});
Extending #Lord Midi code, we can check to see if a window is not destroyed and is still focusable. You can do that with the following code:
let playerWindow;
const isPlayerWindowOpened = () => !playerWindow?.isDestroyed() && playerWindow?.isFocusable();
ipcMain.on("load-video-window", (event, data) => {
if (isPlayerWindowOpened()) {
playerWindow.close();
}
playerWindow = new BrowserWindow();
})
I'm using vue-cli-plugin-electron-builder for my electron app and I try to figure out how would I deal to open a component in a new window, which practically is a video player. The scenario is the following:
I have a list of movie dialogues with start and end timestamps. As I click on start timestamp per row the new window should open and the video player should start.
At this state I'm able to open a new window as it follows:
import { remote } from "electron";
export default {
methods: {
startVideo(id, startTimestamp) {
// eslint-disable-next-line no-console
console.log(id);
// eslint-disable-next-line no-console
console.log(startTimestamp);
let videoPlayerWindow = new remote.BrowserWindow({
show: true,
width: 1440,
height: 900,
webPreferences: { plugins: true }
});
}
}
}
but I don't know how to inject in this case the video-player child component.
I have done something similar so I should be able to set you on the right path here. You may just need to fill in some gaps
You will need to create a sub page using vue-cli.
So in your vue.config.js add
module.exports = {
//...
pages: {
index: 'src/main.js', // your main window
video_player: 'src/video_player/main.js' // your video window
}
}
Then, an example component in your src/video_player/main.js (This is where you would load your video player component)
import Vue from 'vue'
Vue.config.productionTip = false
const ipc = require('electron').ipcRenderer;
new Vue({
render: h => h('div', 'This is your video player, use a component here instead')
}).$mount('#app')
// listen for data from the main process if you want to, put this in your component if necessary
ipc.on('data', (event, data) => {
// use data
})
Now in your main process or src/background.js you will need to add an event listener to open the window from the renderer process.
import { app, protocol, BrowserWindow, ipcMain } from 'electron' // import ipcMain
...
// create the listener
ipcMain.on('load-video-window', (event, data) => {
// create the window
let video_player = new BrowserWindow({ show: true,
width: 1440,
height: 900,
webPreferences: {
nodeIntegration: true,
plugins: true
} })
if (process.env.WEBPACK_DEV_SERVER_URL) {
// Load the url of the dev server if in development mode
video_player.loadURL(process.env.WEBPACK_DEV_SERVER_URL + 'video_player.html')
if (!process.env.IS_TEST) video_player.webContents.openDevTools()
} else {
video_player.loadURL(`app://./video_player`)
}
video_player.on('closed', () => {
video_player = null
})
// here we can send the data to the new window
video_player.webContents.on('did-finish-load', () => {
video_player.webContents.send('data', data);
});
});
Finally, in your renderer process, emit the event to open the window
import { ipcRenderer } from "electron"
export default {
methods: {
startVideo(id, startTimestamp) {
// eslint-disable-next-line no-console
console.log(id);
// eslint-disable-next-line no-console
console.log(startTimestamp);
let data = {id, startTimestamp}
// emit the event
ipcRenderer.send('load-video-window', data);
}
}
}
Hopefully that helps.
Noah Klayman has done a complete example here https://github.com/nklayman/electron-multipage-example.
You will just need to adapt.
I'm using the plugin image-picker for nativescript and I copied the example code to see how it works and to adapt it to my code. But the code doesn't work. When I tap the button it's supposed that the screen gallery from my device should be opened, but nothing happen when I tap the button.
The code below is how I implements this.
album_list.component.ts
import { Component } from '#angular/core';
import { RouterExtensions } from 'nativescript-angular/router';
//image picker
var imagepicker = require("nativescript-imagepicker");
#Component({
selector:'album_list',
moduleId: module.id,
templateUrl: "album_list.component.html",
})
export class AlbumListComponent{
constructor(private routerExt: RouterExtensions ){}
ngOnInit() {
}
onSelectMultipleTap() {
console.log('Im in');
function selectImages() {
var context = imagepicker.create({
mode: "multiple"
});
context
.authorize()
.then(function() {
return context.present();
})
.then(function(selection) {
console.log("Selection done:");
selection.forEach(function(selected) {
console.log(" - " + selected.uri);
});
}).catch(function (e) {
console.log(e);
});
}
}
}
album_list.component.html
<StackLayout>
<Button text="Pick Multiple Images" (tap)="onSelectMultipleTap()" > </Button>
</StackLayout>
As I said, when I tap the button in the html the log from the function onSelectMultipleTap appears, but nothing else.
Thanks!!
You arent calling selectImages(), you just declare it. Replace with this:
onSelectMultipleTap() {
console.log('Im in');
function selectImages() {
var context = imagepicker.create({
mode: "multiple"
});
context
.authorize()
.then(function() {
return context.present();
})
.then(function(selection) {
console.log("Selection done:");
selection.forEach(function(selected) {
console.log(" - " + selected.uri);
});
}).catch(function (e) {
console.log(e);
});
}
selectImages()
}
I had a slightly different issue that only occurred on iOS. I'm working on an upgraded Nativescript project from 4 to 6, and yes I know NS 8 is out right now, but some of the libraries being used aren't supported on the latest NS.
My application had a modal list view that popped up to allow the user to select between camera and gallery, and once the user clicked one of the options the list modal would close. At that time the camera or gallery modal should have appeared but it didn't. What was happening was the closing of the first model was somehow blocking the second modal from opening. My fix was to add a conditional async timeout in my method before calling the context.present(). See my code below:
public takePicture() {
// const options = { width: 1280, height: 720, keepAspectRatio: false, saveToGallery: false};
const self = this;
camera.requestPermissions()
.then(async function () {
//This iOS pause is needed so the camera modal popup will not be stopped by the list option modal closing
if (isIOS) {
await new Promise(resolve => setTimeout(() => resolve(), 1000));
}
})
.then (function() {
camera.takePicture()
.then((imageAsset) => {
const imagePost = new TripMessagePostModel();
ImageSource.fromAsset(imageAsset).then((result) => {
const time = new Date();
imagePost.image = result.toBase64String("jpeg", 50);
imagePost.imageFileName = `${self.userId}-${time.getTime()}.jpeg`;
self.addPost(imagePost);
});
}).catch((err) => {
console.log("Error -> " + err.message);
});
}
)
}
public selectImage() {
const context = imagepicker.create({
mode: "single",
});
const imagePost = new TripMessagePostModel();
context
.authorize()
.then(async function() {
//This iOS pause is needed so the camera modal popup will not be stopped by the list option modal closing
if (isIOS) {
await new Promise(resolve => setTimeout(() => resolve(), 1000));
}
return context.present();
})
.then(function(selection) {
selection.forEach(async (selected) => {
ImageSource.fromAsset(selected).then((result) => {
//console.log(selected.android.toString());
const time = new Date();
imagePost.image = result.toBase64String("jpeg", 40);
imagePost.imageFileName = `${this.userId}-${time.getTime()}.jpeg`;
this.addPost(imagePost);
});
});
}).catch((e) => {
console.log(e);
});
}