1
0
mirror of https://github.com/kremalicious/blowfish.git synced 2024-11-22 09:47:00 +01:00

Merge pull request #214 from kremalicious/nextron

migrate to nextron
This commit is contained in:
Matthias Kretschmann 2020-10-10 17:53:41 +02:00 committed by GitHub
commit f4cb6dc52c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 3400 additions and 4368 deletions

View File

@ -5,14 +5,9 @@
"prettier", "prettier",
"prettier/react" "prettier/react"
], ],
"parser": "babel-eslint",
"plugins": ["react"], "plugins": ["react"],
"rules": {
"quotes": ["error", "single"],
"semi": ["error", "never"]
},
"parserOptions": { "parserOptions": {
"ecmaVersion": 2017, "ecmaVersion": 2020,
"sourceType": "module", "sourceType": "module",
"ecmaFeatures": { "ecmaFeatures": {
"jsx": true "jsx": true

2
.gitignore vendored
View File

@ -1,7 +1,7 @@
node_modules node_modules
build
dist dist
coverage coverage
app
.next .next
out out
.env .env

View File

@ -1,6 +0,0 @@
{
"plugins": ["stylelint-prettier"],
"rules": {
"prettier/prettier": true
}
}

View File

@ -23,7 +23,7 @@ before_script:
script: script:
- npm test || travis_terminate 1 - npm test || travis_terminate 1
- ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
- npm run dist - npm run build
branches: branches:
except: except:

View File

@ -91,20 +91,14 @@ When building the app yourself, you can configure more in the `src/config.js` fi
## Build packages ## Build packages
```bash ```bash
npm run dist npm run build
``` ```
Will build and package the app into platform specific packages for macOS, Windows & Linux. Will build and package the app into platform specific packages for macOS, Windows & Linux.
On a Mac and Linux machine, packaging requires [`wine`](https://www.winehq.org) in your `PATH`. To install on macOS with [Homebrew](https://brew.sh):
```bash
brew install wine
```
## Creating Releases ## Creating Releases
From a clean `main` branch, running any release task will do the following: From a clean `main` branch, running the release task will do the following:
- bumps the project version - bumps the project version
- creates a Git tag - creates a Git tag
@ -112,11 +106,9 @@ From a clean `main` branch, running any release task will do the following:
- creates a GitHub release with commit messages as description - creates a GitHub release with commit messages as description
- adds freshly build binaries for macOS, Windows & Linux as assets to each GitHub release - adds freshly build binaries for macOS, Windows & Linux as assets to each GitHub release
You can execute the script using {major|minor|patch} as first argument to bump the version accordingly: ```bash
npm run release
- To bump a patch version: `npm run release` ```
- To bump a minor version: `npm run release minor`
- To bump a major version: `npm run release major`
For the GitHub releases steps a GitHub personal access token, exported as `GITHUB_TOKEN` is required. [Setup](https://github.com/release-it/release-it#github-releases) For the GitHub releases steps a GitHub personal access token, exported as `GITHUB_TOKEN` is required. [Setup](https://github.com/release-it/release-it#github-releases)

16
electron-builder.json Normal file
View File

@ -0,0 +1,16 @@
{
"appId": "com.kremalicious.blowfish",
"directories": { "buildResources": "./src/resources" },
"files": ["app", "package.json"],
"mac": {
"category": "public.app-category.finance",
"identity": null,
"darkModeSupport": true
},
"linux": {
"target": ["deb", "snap", "AppImage"],
"category": "Office",
"executableName": "Blowfish",
"artifactName": "${productName}-${version}.${ext}"
}
}

4
nextron.config.js Normal file
View File

@ -0,0 +1,4 @@
module.exports = {
mainSrcDir: './src/main',
rendererSrcDir: './src/renderer'
}

7005
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -3,25 +3,21 @@
"productName": "Blowfish", "productName": "Blowfish",
"version": "1.5.2", "version": "1.5.2",
"description": "🐡 Simple Electron-based desktop app to retrieve and display your total Ocean Token balances.", "description": "🐡 Simple Electron-based desktop app to retrieve and display your total Ocean Token balances.",
"main": "./src/main/index.js", "main": "app/background.js",
"scripts": { "scripts": {
"start": "electron .", "start": "nextron",
"build": "nextron build --all",
"postinstall": "electron-builder install-app-deps",
"test": "npm run lint && npm run jest", "test": "npm run lint && npm run jest",
"test:watch": "npm run jest -- --watch", "test:watch": "npm run jest -- --watch",
"jest": "NODE_ENV=test jest -c tests/jest.config.js", "jest": "NODE_ENV=test jest -c tests/jest.config.js",
"lint": "eslint --ignore-path .gitignore ./src/**/*.{js,jsx} && stylelint --ignore-path .gitignore ./src/**/*.{css,scss}", "lint": "eslint --ignore-path .gitignore ./src/**/*.{js,jsx}",
"copy:icons": "copy 'src/renderer/images/icon*' build/", "format": "prettier --write --ignore-path .gitignore 'src/**/*.{js,jsx,json,css,scss}'",
"build:react": "cross-env NODE_ENV=production next build src/renderer && next export src/renderer && npm run copy:icons", "release": "release-it",
"build:electron:mac": "electron-builder build -m -p never", "changelog": "auto-changelog -p"
"build:electron:linux": "electron-builder build -l -p never",
"build:electron:win": "electron-builder build -w -p never",
"dist": "./scripts/release-prepare.sh",
"release": "release-it --non-interactive",
"changelog": "auto-changelog -p",
"format": "prettier --write --ignore-path .gitignore 'src/**/*.{js,jsx,json,css,scss}'"
}, },
"repository": "https://github.com/kremalicious/blowfish.git", "repository": "https://github.com/kremalicious/blowfish.git",
"homepage": "https://github.com/kremalicious/blowfish", "homepage": "https://getblow.fish",
"author": { "author": {
"name": "Matthias Kretschmann", "name": "Matthias Kretschmann",
"email": "m@kretschmann.io", "email": "m@kretschmann.io",
@ -29,12 +25,10 @@
}, },
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@coingecko/cryptoformat": "^0.4.1", "@coingecko/cryptoformat": "^0.4.2",
"@oceanprotocol/contracts": "^0.5.3", "@oceanprotocol/contracts": "^0.5.4",
"axios": "^0.20.0", "axios": "^0.20.0",
"electron-is-dev": "^1.2.0", "electron-store": "^6.0.1",
"electron-next": "^3.1.5",
"electron-store": "^6.0.0",
"ethereum-address": "^0.0.4", "ethereum-address": "^0.0.4",
"ethereum-blockies": "github:MyEtherWallet/blockies", "ethereum-blockies": "github:MyEtherWallet/blockies",
"ethjs": "^0.4.0", "ethjs": "^0.4.0",
@ -43,61 +37,31 @@
"swr": "^0.3.5" "swr": "^0.3.5"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.11.6",
"@babel/preset-env": "^7.11.5",
"@jest-runner/electron": "^3.0.0", "@jest-runner/electron": "^3.0.0",
"@react-mock/state": "^0.1.8", "@react-mock/state": "^0.1.8",
"@svgr/webpack": "^5.4.0", "@svgr/webpack": "^5.4.0",
"@testing-library/jest-dom": "^5.11.4", "@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.0.4", "@testing-library/react": "^11.0.4",
"auto-changelog": "^2.2.1", "auto-changelog": "^2.2.1",
"babel-eslint": "^10.1.0", "babel-jest": "^26.5.2",
"babel-jest": "^26.3.0",
"copy": "^0.3.2",
"cross-env": "^7.0.2",
"dotenv": "^8.2.0", "dotenv": "^8.2.0",
"electron": "^10.1.3", "electron": "^10.1.3",
"electron-builder": "^22.8.1", "electron-builder": "^22.8.1",
"electron-devtools-installer": "^3.1.1", "electron-serve": "^1.0.0",
"eslint": "^7.10.0", "eslint": "^7.11.0",
"eslint-config-prettier": "^6.12.0", "eslint-config-prettier": "^6.12.0",
"eslint-plugin-react": "^7.21.3", "eslint-plugin-react": "^7.21.4",
"identity-obj-proxy": "^3.0.0", "identity-obj-proxy": "^3.0.0",
"jest": "^26.4.2", "jest": "^26.5.2",
"next": "^9.5.3", "next": "9.5.1",
"nextron": "^5.15.2",
"prettier": "^2.1.2", "prettier": "^2.1.2",
"react": "^16.13.1", "react": "^16.13.1",
"react-dom": "^16.13.1", "react-dom": "^16.13.1",
"react-pose": "^4.0.10", "react-pose": "^4.0.10",
"release-it": "^14.0.3", "release-it": "^14.0.4"
"stylelint": "^13.7.2",
"stylelint-prettier": "^1.1.2"
}, },
"browserslist": "electron >= 8.0", "browserslist": "electron >= 8.0",
"build": {
"appId": "com.kremalicious.blowfish",
"files": [
"./src/main/**/*",
"./src/renderer/out/**/*",
"./src/*.js",
"package.json"
],
"mac": {
"category": "public.app-category.finance",
"identity": null,
"darkModeSupport": true
},
"linux": {
"target": [
"deb",
"snap",
"AppImage"
],
"category": "Office",
"executableName": "Blowfish",
"artifactName": "${productName}-${version}.${ext}"
}
},
"release-it": { "release-it": {
"hooks": { "hooks": {
"after:init": "npm test", "after:init": "npm test",

View File

@ -1,29 +0,0 @@
#!/bin/bash
rm -rf {dist,build,src/renderer/.next,src/renderer/out}/ && \
npm run build:react && \
npm run build:electron:mac && \
if [ -x "$(command -v docker)" ]; then
docker run --rm \
--env-file <(env | grep -iE 'DEBUG|NODE_|ELECTRON_|YARN_|NPM_|CI|CIRCLE|TRAVIS_TAG|TRAVIS|TRAVIS_REPO_|TRAVIS_BUILD_|TRAVIS_BRANCH|TRAVIS_PULL_REQUEST_|APPVEYOR_|CSC_|GH_|GITHUB_|BT_|AWS_|STRIP|BUILD_') \
--env ELECTRON_CACHE="/root/.cache/electron" \
--env ELECTRON_BUILDER_CACHE="/root/.cache/electron-builder" \
-v ${PWD}:/project \
-v ${PWD##*/}-node-modules:/project/node_modules \
-v ~/.cache/electron:/root/.cache/electron \
-v ~/.cache/electron-builder:/root/.cache/electron-builder \
electronuserland/builder:wine \
/bin/bash -c "npm i && npm run build:react && npm run build:electron:win"
docker run --rm \
--env-file <(env | grep -iE 'DEBUG|NODE_|ELECTRON_|YARN_|NPM_|CI|CIRCLE|TRAVIS_TAG|TRAVIS|TRAVIS_REPO_|TRAVIS_BUILD_|TRAVIS_BRANCH|TRAVIS_PULL_REQUEST_|APPVEYOR_|CSC_|GH_|GITHUB_|BT_|AWS_|STRIP|BUILD_') \
--env ELECTRON_CACHE="/root/.cache/electron" \
--env ELECTRON_BUILDER_CACHE="/root/.cache/electron-builder" \
-v ${PWD}:/project \
-v ${PWD##*/}-node-modules:/project/node_modules \
-v ~/.cache/electron:/root/.cache/electron \
-v ~/.cache/electron-builder:/root/.cache/electron-builder \
electronuserland/builder:12 \
/bin/bash -c "npm i && npm run build:react && npm run build:electron:linux"
fi

149
src/main/background.js Normal file
View File

@ -0,0 +1,149 @@
import serve from 'electron-serve'
import { app, systemPreferences, nativeTheme, ipcMain } from 'electron'
import { productName } from '../../package.json'
import {
createWindow,
createWindowEvents,
buildMenu,
buildTouchbar,
updateTouchbar
} from './helpers'
import { rgbaToHex } from '../utils'
const isProd = process.env.NODE_ENV === 'production'
if (isProd) {
serve({ directory: 'app' })
} else {
app.setPath('userData', `${app.getPath('userData')} (development)`)
}
let mainWindow
const width = 640
const height = 450
;(async () => {
await app.whenReady()
const isDarkMode = nativeTheme.shouldUseDarkColors
mainWindow = createWindow('main', {
width,
height,
minWidth: width,
minHeight: height,
acceptFirstMouse: true,
titleBarStyle: 'hiddenInset',
fullscreenWindowTitle: true,
backgroundColor: isDarkMode ? '#141414' : '#fff',
frame: process.platform === 'darwin' ? false : true,
show: false,
title: productName,
autoHideMenuBar: true,
webPreferences: {
nodeIntegration: true,
scrollBounce: true,
enableBlinkFeatures: 'OverlayScrollbars',
enableRemoteModule: true
}
})
if (isProd) {
await mainWindow.loadURL('app://./index.html')
} else {
const port = process.argv[2]
await mainWindow.loadURL(`http://localhost:${port}/`)
// mainWindow.webContents.openDevTools()
}
createWindowEvents(mainWindow)
mainWindow.once('ready-to-show', () => {
mainWindow.show()
mainWindow.focus()
})
// Load menu
buildMenu(mainWindow)
// Load touchbar
if (process.platform === 'darwin') {
const accentColor = getAccentColor()
buildTouchbar(mainWindow, accentColor)
ipcMain.on('prices-updated', (event, pricesNew) => {
updateTouchbar(pricesNew, mainWindow, accentColor)
})
ipcMain.on('currency-updated', (event, pricesNew, currentCurrency) => {
updateTouchbar(pricesNew, mainWindow, accentColor, currentCurrency)
})
}
switchAccentColor()
switchTheme()
// add platform as class
mainWindow.webContents.executeJavaScript(
`document.getElementsByTagName('html')[0].classList.add('${process.platform}')`
)
})()
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
//
// Accent color setting
// macOS & Windows
//
const getAccentColor = () => {
const systemAccentColor = systemPreferences.getAccentColor()
return rgbaToHex(systemAccentColor)
}
const switchAccentColor = () => {
if (process.platform !== 'linux') {
const accentColor = getAccentColor()
mainWindow.webContents.send('accent-color', accentColor)
}
}
// Listen for accent color changes in System Preferences
// macOS
if (process.platform === 'darwin') {
systemPreferences.subscribeNotification('AppleAquaColorVariantChanged', () =>
switchAccentColor()
)
}
// Windows
if (process.platform === 'windows') {
systemPreferences.on('accent-color-changed', () => switchAccentColor())
}
//
// Appearance setting
//
const switchTheme = () => {
const isDarkMode = nativeTheme.shouldUseDarkColors
isDarkMode
? mainWindow.webContents.executeJavaScript(
'document.getElementsByTagName("html")[0].classList.add("dark")'
)
: mainWindow.webContents.executeJavaScript(
'document.getElementsByTagName("html")[0].classList.remove("dark")'
)
}
// Listen for appearance changes in System Preferences
if (process.platform === 'darwin') {
systemPreferences.subscribeNotification(
'AppleInterfaceThemeChangedNotification',
() => switchTheme()
)
}

View File

@ -1,8 +1,8 @@
const { app, Menu } = require('electron') import { app, Menu } from 'electron'
const { openUrl } = require('../utils') import { openUrl } from '../../utils'
const { homepage } = require('../../package.json') import { homepage } from '../../../package.json'
const buildMenu = (mainWindow) => { export default function buildMenu(mainWindow) {
const template = [ const template = [
{ {
label: 'Edit', label: 'Edit',
@ -179,5 +179,3 @@ const buildMenu = (mainWindow) => {
const menu = Menu.buildFromTemplate(template) const menu = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(menu) Menu.setApplicationMenu(menu)
} }
module.exports = buildMenu

View File

@ -0,0 +1,22 @@
export default function createWindowEvents(mainWindow) {
mainWindow.on('enter-full-screen', () =>
mainWindow.webContents.executeJavaScript(
'document.getElementsByTagName("html")[0].classList.add("fullscreen")'
)
)
mainWindow.on('leave-full-screen', () =>
mainWindow.webContents.executeJavaScript(
'document.getElementsByTagName("html")[0].classList.remove("fullscreen")'
)
)
mainWindow.on('blur', () =>
mainWindow.webContents.executeJavaScript(
'document.getElementsByTagName("html")[0].classList.add("blur")'
)
)
mainWindow.on('focus', () =>
mainWindow.webContents.executeJavaScript(
'document.getElementsByTagName("html")[0].classList.remove("blur")'
)
)
}

View File

@ -0,0 +1,78 @@
import { screen, BrowserWindow } from 'electron'
import * as Store from 'electron-store'
export default function createWindow(windowName, options) {
const key = 'window-state'
const name = `window-state-${windowName}`
const store = new Store({ name })
const defaultSize = {
width: options.width,
height: options.height
}
let state = {}
let win
const restore = () => store.get(key, defaultSize)
const getCurrentPosition = () => {
const position = win.getPosition()
const size = win.getSize()
return {
x: position[0],
y: position[1],
width: size[0],
height: size[1]
}
}
const windowWithinBounds = (windowState, bounds) => {
return (
windowState.x >= bounds.x &&
windowState.y >= bounds.y &&
windowState.x + windowState.width <= bounds.x + bounds.width &&
windowState.y + windowState.height <= bounds.y + bounds.height
)
}
const resetToDefaults = () => {
const bounds = screen.getPrimaryDisplay().bounds
return Object.assign({}, defaultSize, {
x: (bounds.width - defaultSize.width) / 2,
y: (bounds.height - defaultSize.height) / 2
})
}
const ensureVisibleOnSomeDisplay = (windowState) => {
const visible = screen.getAllDisplays().some((display) => {
return windowWithinBounds(windowState, display.bounds)
})
if (!visible) {
// Window is partially or fully not visible now.
// Reset it to safe defaults.
return resetToDefaults()
}
return windowState
}
const saveState = () => {
if (!win.isMinimized() && !win.isMaximized()) {
Object.assign(state, getCurrentPosition())
}
store.set(key, state)
}
state = ensureVisibleOnSomeDisplay(restore())
win = new BrowserWindow({
...options,
...state,
webPreferences: {
nodeIntegration: true,
...options.webPreferences
}
})
win.on('close', saveState)
return win
}

12
src/main/helpers/index.js Normal file
View File

@ -0,0 +1,12 @@
import createWindow from './create-window'
import createWindowEvents from './create-window-events'
import buildMenu from './build-menu'
import { buildTouchbar, updateTouchbar } from './touchbar'
export {
createWindow,
createWindowEvents,
buildMenu,
buildTouchbar,
updateTouchbar
}

View File

@ -1,6 +1,6 @@
const { TouchBar } = require('electron') import { TouchBar } from 'electron'
const { cryptoFormatter } = require('../utils') import { cryptoFormatter } from '../../utils'
const { conversions } = require('../config') import { conversions } from '../../config'
const { TouchBarButton } = TouchBar const { TouchBarButton } = TouchBar
@ -51,4 +51,4 @@ const updateTouchbar = (
mainWindow.setTouchBar(touchBar) mainWindow.setTouchBar(touchBar)
} }
module.exports = { buildTouchbar, updateTouchbar } export { buildTouchbar, updateTouchbar }

View File

@ -1,214 +0,0 @@
const path = require('path')
const {
app,
BrowserWindow,
systemPreferences,
nativeTheme,
ipcMain
} = require('electron')
const prepareNext = require('electron-next')
const isDev = require('electron-is-dev')
const pkg = require('../../package.json')
const buildMenu = require('./menu')
const { buildTouchbar, updateTouchbar } = require('./touchbar')
const { rgbaToHex } = require('../utils')
let mainWindow
const width = 640
const height = 450
app.allowRendererProcessReuse = true
const createWindow = async () => {
const isDarkMode = nativeTheme.shouldUseDarkColors
mainWindow = new BrowserWindow({
width,
height,
minWidth: width,
minHeight: height,
acceptFirstMouse: true,
titleBarStyle: 'hiddenInset',
fullscreenWindowTitle: true,
backgroundColor: isDarkMode ? '#141414' : '#fff',
frame: process.platform === 'darwin' ? false : true,
show: false,
title: pkg.productName,
autoHideMenuBar: true,
webPreferences: {
nodeIntegration: true,
preload: path.join(__dirname, 'preload.js'),
scrollBounce: true,
enableBlinkFeatures: 'OverlayScrollbars',
enableRemoteModule: true
}
})
mainWindow.loadURL(
isDev
? 'http://localhost:8000'
: `file://${path.join(__dirname, '../renderer/out/index.html')}`
)
createWindowEvents(mainWindow)
installDevTools(mainWindow)
mainWindow.once('ready-to-show', () => {
mainWindow.show()
mainWindow.focus()
})
mainWindow.on('closed', () => {
mainWindow = null
})
// Load menu
buildMenu(mainWindow)
// Load touchbar
if (process.platform === 'darwin') {
const accentColor = getAccentColor()
buildTouchbar(mainWindow, accentColor)
ipcMain.on('prices-updated', (event, pricesNew) => {
updateTouchbar(pricesNew, mainWindow, accentColor)
})
ipcMain.on('currency-updated', (event, pricesNew, currentCurrency) => {
updateTouchbar(pricesNew, mainWindow, accentColor, currentCurrency)
})
}
}
app.on('ready', async () => {
await prepareNext('./src/renderer')
await createWindow()
mainWindow.webContents.on('dom-ready', () => {
switchTheme()
// add platform as class
mainWindow.webContents.executeJavaScript(
`document.getElementsByTagName('html')[0].classList.add('${process.platform}')`
)
})
mainWindow.webContents.on('did-finish-load', () => {
switchAccentColor()
})
})
// Quit when all windows are closed.
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
if (mainWindow === null) {
createWindow()
}
})
const installDevTools = async (mainWindow) => {
if (isDev) {
const {
default: installExtension,
REACT_DEVELOPER_TOOLS
} = require('electron-devtools-installer')
try {
const name = await installExtension(REACT_DEVELOPER_TOOLS)
console.log(`Added Extension: ${name}`) // eslint-disable-line no-console
mainWindow.webContents.on('devtools-opened', () =>
mainWindow.setSize(1024, 420, true)
)
mainWindow.webContents.on('devtools-closed', () =>
mainWindow.setSize(width, height, true)
)
} catch (error) {
console.log('An error occurred: ', error) // eslint-disable-line no-console
}
}
}
const createWindowEvents = (mainWindow) => {
mainWindow.on('enter-full-screen', () =>
mainWindow.webContents.executeJavaScript(
'document.getElementsByTagName("html")[0].classList.add("fullscreen")'
)
)
mainWindow.on('leave-full-screen', () =>
mainWindow.webContents.executeJavaScript(
'document.getElementsByTagName("html")[0].classList.remove("fullscreen")'
)
)
mainWindow.on('blur', () =>
mainWindow.webContents.executeJavaScript(
'document.getElementsByTagName("html")[0].classList.add("blur")'
)
)
mainWindow.on('focus', () =>
mainWindow.webContents.executeJavaScript(
'document.getElementsByTagName("html")[0].classList.remove("blur")'
)
)
}
//
// Accent color setting
// macOS & Windows
//
const getAccentColor = () => {
const systemAccentColor = systemPreferences.getAccentColor()
return rgbaToHex(systemAccentColor)
}
const switchAccentColor = () => {
if (process.platform !== 'linux') {
const accentColor = getAccentColor()
mainWindow.webContents.send('accent-color', accentColor)
}
}
// Listen for accent color changes in System Preferences
// macOS
if (process.platform === 'darwin') {
systemPreferences.subscribeNotification('AppleAquaColorVariantChanged', () =>
switchAccentColor()
)
}
// Windows
if (process.platform === 'windows') {
systemPreferences.on('accent-color-changed', () => switchAccentColor())
}
//
// Appearance setting
// macOS
//
const switchTheme = () => {
if (process.platform === 'darwin') {
const isDarkMode = nativeTheme.shouldUseDarkColors
isDarkMode
? mainWindow.webContents.executeJavaScript(
'document.getElementsByTagName("html")[0].classList.add("dark")'
)
: mainWindow.webContents.executeJavaScript(
'document.getElementsByTagName("html")[0].classList.remove("dark")'
)
}
}
// Listen for appearance changes in System Preferences
if (process.platform === 'darwin') {
systemPreferences.subscribeNotification(
'AppleInterfaceThemeChangedNotification',
() => switchTheme()
)
}

View File

@ -1,12 +0,0 @@
const { webFrame, ipcRenderer } = require('electron')
const Store = require('electron-store')
// Since we disabled nodeIntegration we can reintroduce
// needed node functionality here
process.once('loaded', () => {
const store = new Store()
global.ipcRenderer = ipcRenderer
global.webFrame = webFrame
global.store = store
})

View File

@ -1,5 +1,6 @@
import React, { PureComponent } from 'react' import React, { PureComponent } from 'react'
import ethereum_address from 'ethereum-address' import ethereum_address from 'ethereum-address'
import electron from 'electron'
import Store from 'electron-store' import Store from 'electron-store'
import { AppContext } from '../../../store/createContext' import { AppContext } from '../../../store/createContext'
import Saved from './Saved' import Saved from './Saved'
@ -9,12 +10,12 @@ import styles from './index.module.css'
export default class AccountsList extends PureComponent { export default class AccountsList extends PureComponent {
static contextType = AppContext static contextType = AppContext
store = process.env.NODE_ENV === 'test' ? new Store() : global.store store = (electron.remote && new Store()) || false
state = { accounts: [], input: '', error: '' } state = { accounts: [], input: '', error: '' }
componentDidMount() { componentDidMount() {
if (this.store.has('accounts')) { if (this.store && this.store.has('accounts')) {
this.setState({ accounts: this.store.get('accounts') }) this.setState({ accounts: this.store.get('accounts') })
} }
} }
@ -46,7 +47,7 @@ export default class AccountsList extends PureComponent {
} else { } else {
const joined = [...accounts, input] const joined = [...accounts, input]
this.store.set('accounts', joined) this.store && this.store.set('accounts', joined)
this.setState({ accounts: joined, input: '', error: '' }) this.setState({ accounts: joined, input: '', error: '' })
this.context.setBalances() this.context.setBalances()
} }
@ -63,7 +64,7 @@ export default class AccountsList extends PureComponent {
array.splice(index, 1) array.splice(index, 1)
} }
this.store.set('accounts', array) this.store && this.store.set('accounts', array)
this.setState({ accounts: array }) this.setState({ accounts: array })
this.context.setBalances() this.context.setBalances()
} }

View File

@ -38,12 +38,6 @@ module.exports = withSvgr(
env: { env: {
ETHERSCAN_API_KEY: process.env.ETHERSCAN_API_KEY, ETHERSCAN_API_KEY: process.env.ETHERSCAN_API_KEY,
INFURA_PROJECT_ID: process.env.INFURA_PROJECT_ID INFURA_PROJECT_ID: process.env.INFURA_PROJECT_ID
},
exportPathMap() {
return {
'/': { page: '/' },
'/preferences': { page: '/preferences' }
}
} }
}) })
) )

View File

@ -1,18 +1,21 @@
import React, { useEffect } from 'react' import React, { useEffect } from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import Router from 'next/router' import Router from 'next/router'
// import { ipcRenderer } from 'electron' import electron from 'electron'
import AppProvider from '../store/AppProvider' import AppProvider from '../store/AppProvider'
import PriceProvider from '../store/PriceProvider' import PriceProvider from '../store/PriceProvider'
import Layout from '../Layout' import Layout from '../Layout'
import '../global.css' import '../global.css'
const ipcRenderer = electron.ipcRenderer || false
export default function App({ Component, pageProps }) { export default function App({ Component, pageProps }) {
useEffect(() => { useEffect(() => {
global.ipcRenderer.on('goTo', (evt, route) => { ipcRenderer &&
Router.push(route) ipcRenderer.on('goTo', (evt, route) => {
}) Router.push(route)
})
}, []) }, [])
return ( return (

View File

@ -1,11 +1,13 @@
import React, { useContext, useState, useEffect } from 'react' import React, { useContext, useState, useEffect } from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import ms from 'ms' import ms from 'ms'
// import { ipcRenderer } from 'electron' import electron from 'electron'
import { AppContext, PriceContext } from './createContext' import { AppContext, PriceContext } from './createContext'
import { refreshInterval, conversions } from '../../config' import { refreshInterval, conversions } from '../../config'
import { getAccounts, getBalance } from './helpers' import { getAccounts, getBalance } from './helpers'
const ipcRenderer = electron.ipcRenderer || false
export default function AppProvider({ children }) { export default function AppProvider({ children }) {
const { prices } = useContext(PriceContext) const { prices } = useContext(PriceContext)
const [isLoading, setIsLoading] = useState(true) const [isLoading, setIsLoading] = useState(true)
@ -15,12 +17,25 @@ export default function AppProvider({ children }) {
const [accentColor, setAccentColor] = useState('#f6388a') const [accentColor, setAccentColor] = useState('#f6388a')
const [error, setError] = useState() const [error, setError] = useState()
function toggleCurrencies(currency) {
setCurrency(currency)
const pricesNew = Array.from(prices)
ipcRenderer && ipcRenderer.send('currency-updated', pricesNew, currency)
}
// listener for accent color & touchbar
useEffect(() => { useEffect(() => {
// listener for accent color if (!ipcRenderer) return
if (process.env.NODE_ENV !== 'test') {
global.ipcRenderer.on('accent-color', (evt, accentColor) => { ipcRenderer.on('accent-color', (evt, accentColor) => {
setAccentColor(accentColor) setAccentColor(accentColor)
}) })
ipcRenderer.on('setCurrency', (evt, currency) => toggleCurrencies(currency))
return () => {
ipcRenderer.removeAllListeners('accent-color')
ipcRenderer.removeAllListeners('setCurrency')
} }
}, []) }, [])
@ -36,11 +51,6 @@ export default function AppProvider({ children }) {
console.error(error.message) console.error(error.message)
setError(error.message) setError(error.message)
} }
// listener for touchbar
global.ipcRenderer.on('setCurrency', (evt, currency) =>
toggleCurrencies(currency)
)
} }
init() init()
@ -81,12 +91,6 @@ export default function AppProvider({ children }) {
} }
} }
function toggleCurrencies(currency) {
setCurrency(currency)
const pricesNew = Array.from(prices)
global.ipcRenderer.send('currency-updated', pricesNew, currency)
}
const context = { const context = {
isLoading, isLoading,
accounts, accounts,

View File

@ -6,6 +6,9 @@ import { fetchData } from '../../utils'
import { convertPrices } from './helpers' import { convertPrices } from './helpers'
import useSWR from 'swr' import useSWR from 'swr'
import ms from 'ms' import ms from 'ms'
import electron from 'electron'
const ipcRenderer = electron.ipcRenderer || false
export default function PriceProvider({ children }) { export default function PriceProvider({ children }) {
// construct initial prices Map to get consistent // construct initial prices Map to get consistent
@ -40,7 +43,7 @@ export default function PriceProvider({ children }) {
setPrices(newPrices) setPrices(newPrices)
setPriceChanges(newPriceChanges) setPriceChanges(newPriceChanges)
global.ipcRenderer.send('prices-updated', Array.from(newPrices)) // convert Map to array, ipc messages seem to kill it ipcRenderer && ipcRenderer.send('prices-updated', Array.from(newPrices)) // convert Map to array, ipc messages seem to kill it
} }
useEffect(() => { useEffect(() => {

View File

@ -1,3 +1,4 @@
import electron from 'electron'
import Store from 'electron-store' import Store from 'electron-store'
import Eth from 'ethjs' import Eth from 'ethjs'
import { oceanTokenContract, conversions } from '../../config' import { oceanTokenContract, conversions } from '../../config'
@ -30,9 +31,10 @@ export async function getBalance(account) {
export async function getAccounts() { export async function getAccounts() {
let needsConfig let needsConfig
let accountsPref let accountsPref
const store = process.env.NODE_ENV === 'test' ? new Store() : global.store
if (store.has('accounts')) { const store = (electron.remote && new Store()) || false
if (store && store.has('accounts')) {
accountsPref = store.get('accounts') accountsPref = store.get('accounts')
needsConfig = !accountsPref.length needsConfig = !accountsPref.length
} else { } else {

View File

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

View File

Before

Width:  |  Height:  |  Size: 145 KiB

After

Width:  |  Height:  |  Size: 145 KiB

View File

@ -1,6 +1,6 @@
const { app, shell } = require('electron') import { app, shell } from 'electron'
const { formatCurrency } = require('@coingecko/cryptoformat') import { formatCurrency } from '@coingecko/cryptoformat'
const axios = require('axios') import axios from 'axios'
const fetchData = async (url) => { const fetchData = async (url) => {
try { try {
@ -75,7 +75,7 @@ const cryptoFormatter = (value, currency) => {
} }
} }
module.exports = { export {
openUrl, openUrl,
rgbaToHex, rgbaToHex,
locale, locale,

View File

@ -1,10 +1,5 @@
import React from 'react' import React from 'react'
import { import { render, fireEvent, waitFor } from '@testing-library/react'
render,
waitForElementToBeRemoved,
fireEvent,
wait
} from '@testing-library/react'
import AppProvider from '../src/renderer/store/AppProvider' import AppProvider from '../src/renderer/store/AppProvider'
import PriceProvider from '../src/renderer/store/PriceProvider' import PriceProvider from '../src/renderer/store/PriceProvider'
import { PriceContext, AppContext } from '../src/renderer/store/createContext' import { PriceContext, AppContext } from '../src/renderer/store/createContext'
@ -20,7 +15,6 @@ describe('Providers', () => {
</PriceContext.Consumer> </PriceContext.Consumer>
</PriceProvider> </PriceProvider>
) )
await waitForElementToBeRemoved(() => getByText(/"eur":0/))
expect(getByText(/eur/)).toBeInTheDocument() expect(getByText(/eur/)).toBeInTheDocument()
}) })
}) })
@ -38,7 +32,7 @@ describe('Providers', () => {
</AppProvider> </AppProvider>
</PriceContext.Provider> </PriceContext.Provider>
) )
await wait(() => getByText('Click')) await waitFor(() => getByText('Click'))
expect(getByText('Click')).toBeInTheDocument() expect(getByText('Click')).toBeInTheDocument()
fireEvent.click(getByText('Click')) fireEvent.click(getByText('Click'))

View File

@ -1,3 +1,4 @@
module.exports = { module.exports = {
has: () => jest.fn() has: () => jest.fn(),
get: () => jest.fn()
} }

View File

@ -14,7 +14,7 @@ module.exports = {
'<rootDir>/src/renderer/.next', '<rootDir>/src/renderer/.next',
'<rootDir>/src/renderer/out', '<rootDir>/src/renderer/out',
'<rootDir>/node_modules', '<rootDir>/node_modules',
'<rootDir>/build', '<rootDir>/app',
'<rootDir>/dist', '<rootDir>/dist',
'<rootDir>/coverage' '<rootDir>/coverage'
], ],