πŸ“œ ⬆️ ⬇️

Own VPN client on JavaScript. 6 part - Electron component Notify

PS Each part is a part, by itself it does not make sense to get the necessary context and not to experience cognitive dissonance from the lack of so necessary blocks of text, start reading from part 1

Notify - Electron component , the element of the presentation of notifications.

Folder structure

notify β”‚ β”‚ index.js β”‚ └───client //      β”‚ fly.html β”‚ static.html β”‚ style.css β”‚ └───fonts font1.woff2 font2.woff2 font3.woff2 font4.woff2 font5.woff2 font6.woff2 font7.woff2 


index.js - The file in which the Electron component is created.
')
Contents of the index.js file.

Code
 const { BrowserWindow, ipcMain } = require('electron') module.exports = class Notification { constructor(parent) { const window_tmp = { frame: false, //   transparent: true, //   resizable: false, //   show: false, //      focusable: true, //     height: 175, width: 200, maxWidth: 200, parent } //   this.root = new BrowserWindow(window_tmp) this.root2 = new BrowserWindow(window_tmp) //      this.root.loadURL(`${__dirname}/client/fly.html`) //   this.root2.loadURL(`${__dirname}/client/static.html`) //      this.type = 'fly' //      confirm  //         alert this.waitingConfirm = 0 } ready() { //      return Promise.all([ new Promise(res => { this.root.once('ready-to-show', res) }), new Promise(res => { this.root2.once('ready-to-show', res) }) ]) } setType(value) { //     this.hide() this.type = value } hide() { //    this.root.hide() this.root2.hide() } alert(message = 'message', hideTime = 6000, callback = () => {}) { //    confirm  if (this.waitingConfirm) { return } //    clearTimeout(this.t) //    this.hide() //           const ROOT = this.type == 'fly' ? 'root' : 'root2' //  ALERT     this[ROOT].webContents.send('ALERT', message) //   this[ROOT].show() //     this[ROOT].blur() //  ROOT    hideTime    callback this.t = setTimeout(() => { this[ROOT].hide() callback() }, hideTime) //      ALERT_HIDE    // ,       callback ipcMain.once('ALERT_HIDE', () => { clearTimeout(this.t) this[ROOT].hide() callback() }) } confirm(message, button, callback) { //    clearTimeout(this.t) //   this.waitingConfirm = 1 //    this.hide() //           const ROOT = this.type == 'fly' ? 'root' : 'root2' //   this[ROOT].show() //     this[ROOT].blur() //  ALERT       this[ROOT].webContents.send('CONFIRM', JSON.stringify({ message, button })) //      CONFIRM_CALLBACK    //    callback     data //       ipcMain.once('CONFIRM_CALLBACK', (e, data) => { //   this.waitingConfirm = 0 try { this[ROOT].hide() callback(data) } catch (e) {} }) } } 


fly.html - HTML page for fly notifications.

Content of the fly.html file.

Code
 <!DOCTYPE html> <html lang='en'> <head> <meta charset='UTF-8'> <link rel='stylesheet' type='text/css' href='style.css'> </head> <body> <div class='body'> <div class='message-box'> <div class='message'> <div class='text'> ...</div> <div class='other'> </div> </div> <div class='vector-box'> <div class='vector'></div> </div> </div> </div> <script> const Text = document.getElementsByClassName('text')[0] , Other = document.getElementsByClassName('other')[0] , { ipcRenderer, remote } = require('electron') //     const win = remote.getCurrentWindow() //        vpn setInterval(() => { win.setPosition( parseInt(localStorage.x - 43), parseInt(localStorage.y - 150) ) }, 3) //      "alert" ipcRenderer.on('ALERT', (e, data) => { Text.innerHTML = data Other.innerHTML = '' }) //      "confirm" ipcRenderer.on('CONFIRM', (e, data) => { const { message, button } = JSON.parse(data) Text.innerHTML = message Other.innerHTML = '' //   button.forEach(elem => { const btn = document.createElement('div') btn.className = 'btn' btn.innerHTML = elem.title btn.onclick = e => { ipcRenderer.send('CONFIRM_CALLBACK', elem.return) e.stopPropagation() } Other.appendChild(btn) }) }) //        document.body.addEventListener('click', () => { ipcRenderer.send('ALERT_HIDE') }) </script> </body> </html> 


static.html - HTML page of the static notifications window.

The contents of the static.html file.

Code
 <!DOCTYPE html> <html lang='en'> <head> <meta charset='UTF-8'> <link rel='stylesheet' type='text/css' href='style.css'> </head> <body> <div class='body'> <div class='message-box'> <div class='message'> <div class='text'> ...</div> <div class='other'> </div> </div> </div> </div> <script> const Text = document.getElementsByClassName('text')[0] , Other = document.getElementsByClassName('other')[0] , Body = document.getElementsByClassName('body')[0] , { ipcRenderer, remote } = require('electron') //     const win = remote.getCurrentWindow() //    const padding = 13 setInterval(() => { //    const static_notify = JSON.parse(localStorage.vpn_setting || "{}").PositionNotify || 'BR' const quickLaunch_Width = (window.screen.width - window.screen.availWidth), quickLaunch_Height = (window.screen.height - window.screen.availHeight), screen_Width = window.screen.width, screen_Height = window.screen.height, notify_Width = 200, notify_Heigth = 175 //   if (static_notify == 'BR') { win.setPosition( (screen_Width - quickLaunch_Width) - (notify_Width + padding), (screen_Height - quickLaunch_Height) - (notify_Heigth + padding) ) Body.style.alignItems = 'flex-end' Body.style.justifyContent = 'flex-end' } //   if (static_notify == 'TR') { win.setPosition((screen_Width - quickLaunch_Width) - (notify_Width + padding), quickLaunch_Height + padding) Body.style.alignItems = 'flex-end' Body.style.justifyContent = 'flex-start' } //   if (static_notify == 'TL') { win.setPosition(quickLaunch_Width + padding, quickLaunch_Height + padding) Body.style.alignItems = 'flex-start' Body.style.justifyContent = 'flex-start' } //   if (static_notify == 'BL') { win.setPosition(quickLaunch_Width + padding, window.screen.availHeight - 188) Body.style.alignItems = 'flex-start' Body.style.justifyContent = 'flex-end' } }, 100) //      "alert" ipcRenderer.on('ALERT', (e, data) => { Text.innerHTML = data Other.innerHTML = '' }) //      "confirm" ipcRenderer.on('CONFIRM', (e, data) => { const { message, button } = JSON.parse(data) Text.innerHTML = message Other.innerHTML = '' //   button.forEach(elem => { const btn = document.createElement('div') btn.className = 'btn' btn.innerHTML = elem.title btn.onclick = e => { ipcRenderer.send('CONFIRM_CALLBACK', elem.return) e.stopPropagation() } Other.appendChild(btn) }) }) //       document.body.addEventListener('click', () => { ipcRenderer.send('ALERT_HIDE') }) </script> </body> </html> 


style.css - Styles for pages.

Content of the style.css file

Code
 @font-face { font-family: 'Source Sans Pro'; font-style: normal; font-weight: 400; src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(fonts/font1.woff2) format('woff2'); unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } @font-face { font-family: 'Source Sans Pro'; font-style: normal; font-weight: 400; src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(fonts/font2.woff2) format('woff2'); unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } @font-face { font-family: 'Source Sans Pro'; font-style: normal; font-weight: 400; src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(fonts/font3.woff2) format('woff2'); unicode-range: U+1F00-1FFF; } @font-face { font-family: 'Source Sans Pro'; font-style: normal; font-weight: 400; src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(fonts/font4.woff2) format('woff2'); unicode-range: U+0370-03FF; } @font-face { font-family: 'Source Sans Pro'; font-style: normal; font-weight: 400; src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(fonts/font5.woff2) format('woff2'); unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; } @font-face { font-family: 'Source Sans Pro'; font-style: normal; font-weight: 400; src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(fonts/font6.woff2) format('woff2'); unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; } @font-face { font-family: 'Source Sans Pro'; font-style: normal; font-weight: 400; src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(fonts/font7.woff2) format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } * { font-family: 'Source Sans Pro', sans-serif; padding: 0; margin: 0; overflow: hidden; background: rgba(0, 0, 0, 0); } .body { display: flex; justify-content: flex-end; align-items: center; flex-direction: column; height: 175px; } .message-box { display: flex; justify-content: center; align-items: center; flex-direction: column; } .message { border-radius: 10px; font-size: 14px; background: rgba(36, 39, 39, 0.9); padding: 10px 10px 10px 10px; color: #eee; width: auto; max-width: 180px; min-width: 40px; } .other { display: flex; justify-content: space-between; align-items: center; } .btn { min-width: 35px; width: 100%; color: #dcdcdc; background: #7b7b7b; margin: 8px 2px 0px 2px; padding: 3px; font-size: 13px; border-radius: 3px; text-align: center; user-select: none; cursor: pointer; } .button:hover { background: #e6e6e6; background: #868686; } input { cursor: pointer; border: none; border-radius: 6px; padding: 4px 10px 4px 10px; margin: 2px; color: #eee; outline: none; background: rgba(51, 55, 55, 0.9); } input:hover { color: #ccc } .vector { width: 30px; height: 30px; background: rgba(36, 39, 39, 0.9); transform: rotateZ(45deg); border-radius: 5px; } .vector-box { padding: 4px; margin-top: 0px; height: 8px; overflow: hidden; position: relative; z-index: 0; transform: rotateZ(180deg); } 


Application

Application usage: / app / Notify .

API

Interface component Notify. In this example, the organization of the code I was talking about should be seen more clearly.

 const { app } = require('electron') , VPN = require('./../../app/components/vpn') , NOTIFY = require('./../../app/components/notify') app.on('ready', async() => { const Vpn = new VPN() , Notify = new NOTIFY(Vpn.root) //          await Promise.all([ Notify.ready(), Vpn.ready() ]) Vpn.show() Vpn.showTray() const CONFIRN_FSB = [{ title: '', return: ',  !' }, { title: '', return: false }] setTimeout(() => { //   "alert" Notify.alert('  !', 3000, () => { //   "confirm" Notify.confirm('    VPN', CONFIRN_FSB, data => { console.log(data) if (data == false) { //    Notify.setType('static') //   "confirm" Notify.confirm('   ?', CONFIRN_FSB, data => { if (data != false) { app.quit() } }) } else { Vpn.setStatus('resolve', 'blue') } }) }) }, 2000) //    // Notify.setType('static') //   "alert" // Notify.alert('  !', 3000, () => {}) //   "confirm" //Notify.confirm('    VPN', CONFIRN_FSB, console.log) }) 

Test

Test version: / app_test / Notify .

image

Notification types Notify.setType .
Type ofDescription
staticA notification pops up on one of four sides of the screen.
flyThe notification that always pops up above the main window

Part 7 - Context Component


VPN   JavaScript by JSus

Source: https://habr.com/ru/post/429436/


All Articles