mirror of
https://github.com/kremalicious/blowfish.git
synced 2024-11-22 01:36:58 +01:00
commit
f4cb6dc52c
@ -5,14 +5,9 @@
|
||||
"prettier",
|
||||
"prettier/react"
|
||||
],
|
||||
"parser": "babel-eslint",
|
||||
"plugins": ["react"],
|
||||
"rules": {
|
||||
"quotes": ["error", "single"],
|
||||
"semi": ["error", "never"]
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2017,
|
||||
"ecmaVersion": 2020,
|
||||
"sourceType": "module",
|
||||
"ecmaFeatures": {
|
||||
"jsx": true
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,7 +1,7 @@
|
||||
node_modules
|
||||
build
|
||||
dist
|
||||
coverage
|
||||
app
|
||||
.next
|
||||
out
|
||||
.env
|
||||
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"plugins": ["stylelint-prettier"],
|
||||
"rules": {
|
||||
"prettier/prettier": true
|
||||
}
|
||||
}
|
@ -23,7 +23,7 @@ before_script:
|
||||
script:
|
||||
- npm test || travis_terminate 1
|
||||
- ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
|
||||
- npm run dist
|
||||
- npm run build
|
||||
|
||||
branches:
|
||||
except:
|
||||
|
18
README.md
18
README.md
@ -91,20 +91,14 @@ When building the app yourself, you can configure more in the `src/config.js` fi
|
||||
## Build packages
|
||||
|
||||
```bash
|
||||
npm run dist
|
||||
npm run build
|
||||
```
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
- 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
|
||||
- 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:
|
||||
|
||||
- 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`
|
||||
```bash
|
||||
npm run release
|
||||
```
|
||||
|
||||
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
16
electron-builder.json
Normal 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
4
nextron.config.js
Normal file
@ -0,0 +1,4 @@
|
||||
module.exports = {
|
||||
mainSrcDir: './src/main',
|
||||
rendererSrcDir: './src/renderer'
|
||||
}
|
7005
package-lock.json
generated
7005
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
76
package.json
76
package.json
@ -3,25 +3,21 @@
|
||||
"productName": "Blowfish",
|
||||
"version": "1.5.2",
|
||||
"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": {
|
||||
"start": "electron .",
|
||||
"start": "nextron",
|
||||
"build": "nextron build --all",
|
||||
"postinstall": "electron-builder install-app-deps",
|
||||
"test": "npm run lint && npm run jest",
|
||||
"test:watch": "npm run jest -- --watch",
|
||||
"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}",
|
||||
"copy:icons": "copy 'src/renderer/images/icon*' build/",
|
||||
"build:react": "cross-env NODE_ENV=production next build src/renderer && next export src/renderer && npm run copy:icons",
|
||||
"build:electron:mac": "electron-builder build -m -p never",
|
||||
"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}'"
|
||||
"lint": "eslint --ignore-path .gitignore ./src/**/*.{js,jsx}",
|
||||
"format": "prettier --write --ignore-path .gitignore 'src/**/*.{js,jsx,json,css,scss}'",
|
||||
"release": "release-it",
|
||||
"changelog": "auto-changelog -p"
|
||||
},
|
||||
"repository": "https://github.com/kremalicious/blowfish.git",
|
||||
"homepage": "https://github.com/kremalicious/blowfish",
|
||||
"homepage": "https://getblow.fish",
|
||||
"author": {
|
||||
"name": "Matthias Kretschmann",
|
||||
"email": "m@kretschmann.io",
|
||||
@ -29,12 +25,10 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@coingecko/cryptoformat": "^0.4.1",
|
||||
"@oceanprotocol/contracts": "^0.5.3",
|
||||
"@coingecko/cryptoformat": "^0.4.2",
|
||||
"@oceanprotocol/contracts": "^0.5.4",
|
||||
"axios": "^0.20.0",
|
||||
"electron-is-dev": "^1.2.0",
|
||||
"electron-next": "^3.1.5",
|
||||
"electron-store": "^6.0.0",
|
||||
"electron-store": "^6.0.1",
|
||||
"ethereum-address": "^0.0.4",
|
||||
"ethereum-blockies": "github:MyEtherWallet/blockies",
|
||||
"ethjs": "^0.4.0",
|
||||
@ -43,61 +37,31 @@
|
||||
"swr": "^0.3.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.11.6",
|
||||
"@babel/preset-env": "^7.11.5",
|
||||
"@jest-runner/electron": "^3.0.0",
|
||||
"@react-mock/state": "^0.1.8",
|
||||
"@svgr/webpack": "^5.4.0",
|
||||
"@testing-library/jest-dom": "^5.11.4",
|
||||
"@testing-library/react": "^11.0.4",
|
||||
"auto-changelog": "^2.2.1",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"babel-jest": "^26.3.0",
|
||||
"copy": "^0.3.2",
|
||||
"cross-env": "^7.0.2",
|
||||
"babel-jest": "^26.5.2",
|
||||
"dotenv": "^8.2.0",
|
||||
"electron": "^10.1.3",
|
||||
"electron-builder": "^22.8.1",
|
||||
"electron-devtools-installer": "^3.1.1",
|
||||
"eslint": "^7.10.0",
|
||||
"electron-serve": "^1.0.0",
|
||||
"eslint": "^7.11.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",
|
||||
"jest": "^26.4.2",
|
||||
"next": "^9.5.3",
|
||||
"jest": "^26.5.2",
|
||||
"next": "9.5.1",
|
||||
"nextron": "^5.15.2",
|
||||
"prettier": "^2.1.2",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
"react-pose": "^4.0.10",
|
||||
"release-it": "^14.0.3",
|
||||
"stylelint": "^13.7.2",
|
||||
"stylelint-prettier": "^1.1.2"
|
||||
"release-it": "^14.0.4"
|
||||
},
|
||||
"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": {
|
||||
"hooks": {
|
||||
"after:init": "npm test",
|
||||
|
@ -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
149
src/main/background.js
Normal 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()
|
||||
)
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
const { app, Menu } = require('electron')
|
||||
const { openUrl } = require('../utils')
|
||||
const { homepage } = require('../../package.json')
|
||||
import { app, Menu } from 'electron'
|
||||
import { openUrl } from '../../utils'
|
||||
import { homepage } from '../../../package.json'
|
||||
|
||||
const buildMenu = (mainWindow) => {
|
||||
export default function buildMenu(mainWindow) {
|
||||
const template = [
|
||||
{
|
||||
label: 'Edit',
|
||||
@ -179,5 +179,3 @@ const buildMenu = (mainWindow) => {
|
||||
const menu = Menu.buildFromTemplate(template)
|
||||
Menu.setApplicationMenu(menu)
|
||||
}
|
||||
|
||||
module.exports = buildMenu
|
22
src/main/helpers/create-window-events.js
Normal file
22
src/main/helpers/create-window-events.js
Normal 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")'
|
||||
)
|
||||
)
|
||||
}
|
78
src/main/helpers/create-window.js
Normal file
78
src/main/helpers/create-window.js
Normal 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
12
src/main/helpers/index.js
Normal 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
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
const { TouchBar } = require('electron')
|
||||
const { cryptoFormatter } = require('../utils')
|
||||
const { conversions } = require('../config')
|
||||
import { TouchBar } from 'electron'
|
||||
import { cryptoFormatter } from '../../utils'
|
||||
import { conversions } from '../../config'
|
||||
|
||||
const { TouchBarButton } = TouchBar
|
||||
|
||||
@ -51,4 +51,4 @@ const updateTouchbar = (
|
||||
mainWindow.setTouchBar(touchBar)
|
||||
}
|
||||
|
||||
module.exports = { buildTouchbar, updateTouchbar }
|
||||
export { buildTouchbar, updateTouchbar }
|
@ -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()
|
||||
)
|
||||
}
|
@ -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
|
||||
})
|
@ -1,5 +1,6 @@
|
||||
import React, { PureComponent } from 'react'
|
||||
import ethereum_address from 'ethereum-address'
|
||||
import electron from 'electron'
|
||||
import Store from 'electron-store'
|
||||
import { AppContext } from '../../../store/createContext'
|
||||
import Saved from './Saved'
|
||||
@ -9,12 +10,12 @@ import styles from './index.module.css'
|
||||
export default class AccountsList extends PureComponent {
|
||||
static contextType = AppContext
|
||||
|
||||
store = process.env.NODE_ENV === 'test' ? new Store() : global.store
|
||||
store = (electron.remote && new Store()) || false
|
||||
|
||||
state = { accounts: [], input: '', error: '' }
|
||||
|
||||
componentDidMount() {
|
||||
if (this.store.has('accounts')) {
|
||||
if (this.store && this.store.has('accounts')) {
|
||||
this.setState({ accounts: this.store.get('accounts') })
|
||||
}
|
||||
}
|
||||
@ -46,7 +47,7 @@ export default class AccountsList extends PureComponent {
|
||||
} else {
|
||||
const joined = [...accounts, input]
|
||||
|
||||
this.store.set('accounts', joined)
|
||||
this.store && this.store.set('accounts', joined)
|
||||
this.setState({ accounts: joined, input: '', error: '' })
|
||||
this.context.setBalances()
|
||||
}
|
||||
@ -63,7 +64,7 @@ export default class AccountsList extends PureComponent {
|
||||
array.splice(index, 1)
|
||||
}
|
||||
|
||||
this.store.set('accounts', array)
|
||||
this.store && this.store.set('accounts', array)
|
||||
this.setState({ accounts: array })
|
||||
this.context.setBalances()
|
||||
}
|
||||
|
@ -38,12 +38,6 @@ module.exports = withSvgr(
|
||||
env: {
|
||||
ETHERSCAN_API_KEY: process.env.ETHERSCAN_API_KEY,
|
||||
INFURA_PROJECT_ID: process.env.INFURA_PROJECT_ID
|
||||
},
|
||||
exportPathMap() {
|
||||
return {
|
||||
'/': { page: '/' },
|
||||
'/preferences': { page: '/preferences' }
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
@ -1,18 +1,21 @@
|
||||
import React, { useEffect } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import Router from 'next/router'
|
||||
// import { ipcRenderer } from 'electron'
|
||||
import electron from 'electron'
|
||||
import AppProvider from '../store/AppProvider'
|
||||
import PriceProvider from '../store/PriceProvider'
|
||||
import Layout from '../Layout'
|
||||
|
||||
import '../global.css'
|
||||
|
||||
const ipcRenderer = electron.ipcRenderer || false
|
||||
|
||||
export default function App({ Component, pageProps }) {
|
||||
useEffect(() => {
|
||||
global.ipcRenderer.on('goTo', (evt, route) => {
|
||||
Router.push(route)
|
||||
})
|
||||
ipcRenderer &&
|
||||
ipcRenderer.on('goTo', (evt, route) => {
|
||||
Router.push(route)
|
||||
})
|
||||
}, [])
|
||||
|
||||
return (
|
||||
|
@ -1,11 +1,13 @@
|
||||
import React, { useContext, useState, useEffect } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import ms from 'ms'
|
||||
// import { ipcRenderer } from 'electron'
|
||||
import electron from 'electron'
|
||||
import { AppContext, PriceContext } from './createContext'
|
||||
import { refreshInterval, conversions } from '../../config'
|
||||
import { getAccounts, getBalance } from './helpers'
|
||||
|
||||
const ipcRenderer = electron.ipcRenderer || false
|
||||
|
||||
export default function AppProvider({ children }) {
|
||||
const { prices } = useContext(PriceContext)
|
||||
const [isLoading, setIsLoading] = useState(true)
|
||||
@ -15,12 +17,25 @@ export default function AppProvider({ children }) {
|
||||
const [accentColor, setAccentColor] = useState('#f6388a')
|
||||
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(() => {
|
||||
// listener for accent color
|
||||
if (process.env.NODE_ENV !== 'test') {
|
||||
global.ipcRenderer.on('accent-color', (evt, accentColor) => {
|
||||
setAccentColor(accentColor)
|
||||
})
|
||||
if (!ipcRenderer) return
|
||||
|
||||
ipcRenderer.on('accent-color', (evt, 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)
|
||||
setError(error.message)
|
||||
}
|
||||
|
||||
// listener for touchbar
|
||||
global.ipcRenderer.on('setCurrency', (evt, currency) =>
|
||||
toggleCurrencies(currency)
|
||||
)
|
||||
}
|
||||
|
||||
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 = {
|
||||
isLoading,
|
||||
accounts,
|
||||
|
@ -6,6 +6,9 @@ import { fetchData } from '../../utils'
|
||||
import { convertPrices } from './helpers'
|
||||
import useSWR from 'swr'
|
||||
import ms from 'ms'
|
||||
import electron from 'electron'
|
||||
|
||||
const ipcRenderer = electron.ipcRenderer || false
|
||||
|
||||
export default function PriceProvider({ children }) {
|
||||
// construct initial prices Map to get consistent
|
||||
@ -40,7 +43,7 @@ export default function PriceProvider({ children }) {
|
||||
|
||||
setPrices(newPrices)
|
||||
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(() => {
|
||||
|
@ -1,3 +1,4 @@
|
||||
import electron from 'electron'
|
||||
import Store from 'electron-store'
|
||||
import Eth from 'ethjs'
|
||||
import { oceanTokenContract, conversions } from '../../config'
|
||||
@ -30,9 +31,10 @@ export async function getBalance(account) {
|
||||
export async function getAccounts() {
|
||||
let needsConfig
|
||||
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')
|
||||
needsConfig = !accountsPref.length
|
||||
} else {
|
||||
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 145 KiB After Width: | Height: | Size: 145 KiB |
@ -1,6 +1,6 @@
|
||||
const { app, shell } = require('electron')
|
||||
const { formatCurrency } = require('@coingecko/cryptoformat')
|
||||
const axios = require('axios')
|
||||
import { app, shell } from 'electron'
|
||||
import { formatCurrency } from '@coingecko/cryptoformat'
|
||||
import axios from 'axios'
|
||||
|
||||
const fetchData = async (url) => {
|
||||
try {
|
||||
@ -75,7 +75,7 @@ const cryptoFormatter = (value, currency) => {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
export {
|
||||
openUrl,
|
||||
rgbaToHex,
|
||||
locale,
|
||||
|
@ -1,10 +1,5 @@
|
||||
import React from 'react'
|
||||
import {
|
||||
render,
|
||||
waitForElementToBeRemoved,
|
||||
fireEvent,
|
||||
wait
|
||||
} from '@testing-library/react'
|
||||
import { render, fireEvent, waitFor } from '@testing-library/react'
|
||||
import AppProvider from '../src/renderer/store/AppProvider'
|
||||
import PriceProvider from '../src/renderer/store/PriceProvider'
|
||||
import { PriceContext, AppContext } from '../src/renderer/store/createContext'
|
||||
@ -20,7 +15,6 @@ describe('Providers', () => {
|
||||
</PriceContext.Consumer>
|
||||
</PriceProvider>
|
||||
)
|
||||
await waitForElementToBeRemoved(() => getByText(/"eur":0/))
|
||||
expect(getByText(/eur/)).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
@ -38,7 +32,7 @@ describe('Providers', () => {
|
||||
</AppProvider>
|
||||
</PriceContext.Provider>
|
||||
)
|
||||
await wait(() => getByText('Click'))
|
||||
await waitFor(() => getByText('Click'))
|
||||
expect(getByText('Click')).toBeInTheDocument()
|
||||
|
||||
fireEvent.click(getByText('Click'))
|
||||
|
@ -1,3 +1,4 @@
|
||||
module.exports = {
|
||||
has: () => jest.fn()
|
||||
has: () => jest.fn(),
|
||||
get: () => jest.fn()
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ module.exports = {
|
||||
'<rootDir>/src/renderer/.next',
|
||||
'<rootDir>/src/renderer/out',
|
||||
'<rootDir>/node_modules',
|
||||
'<rootDir>/build',
|
||||
'<rootDir>/app',
|
||||
'<rootDir>/dist',
|
||||
'<rootDir>/coverage'
|
||||
],
|
||||
|
Loading…
Reference in New Issue
Block a user