Initial commit
the build was successful Details

master
PHENOM 2018-07-16 04:59:14 +02:00
commit 00a7b46bc8
45 changed files with 2017 additions and 0 deletions

30
.babelrc 100644
View File

@ -0,0 +1,30 @@
{
"comments": false,
"env": {
"main": {
"presets": [
["env", {
"targets": { "node": 7 }
}],
"stage-0"
]
},
"renderer": {
"presets": [
["env", {
"modules": false
}],
"stage-0"
]
},
"web": {
"presets": [
["env", {
"modules": false
}],
"stage-0"
]
}
},
"plugins": ["transform-runtime"]
}

6
.drone.yml 100644
View File

@ -0,0 +1,6 @@
pipeline:
build:
image: node
commands:
- yarn install --network-timeout 1000000
- yarn run build:web

View File

@ -0,0 +1,130 @@
'use strict'
process.env.NODE_ENV = 'production'
const { say } = require('cfonts')
const chalk = require('chalk')
const del = require('del')
const { spawn } = require('child_process')
const webpack = require('webpack')
const Multispinner = require('multispinner')
const mainConfig = require('./webpack.main.config')
const rendererConfig = require('./webpack.renderer.config')
const webConfig = require('./webpack.web.config')
const doneLog = chalk.bgGreen.white(' DONE ') + ' '
const errorLog = chalk.bgRed.white(' ERROR ') + ' '
const okayLog = chalk.bgBlue.white(' OKAY ') + ' '
const isCI = process.env.CI || false
if (process.env.BUILD_TARGET === 'clean') clean()
else if (process.env.BUILD_TARGET === 'web') web()
else build()
function clean () {
del.sync(['build/*', '!build/icons', '!build/icons/icon.*'])
console.log(`\n${doneLog}\n`)
process.exit()
}
function build () {
greeting()
del.sync(['dist/electron/*', '!.gitkeep'])
const tasks = ['main', 'renderer']
const m = new Multispinner(tasks, {
preText: 'building',
postText: 'process'
})
let results = ''
m.on('success', () => {
process.stdout.write('\x1B[2J\x1B[0f')
console.log(`\n\n${results}`)
console.log(`${okayLog}take it away ${chalk.yellow('`electron-builder`')}\n`)
process.exit()
})
pack(mainConfig).then(result => {
results += result + '\n\n'
m.success('main')
}).catch(err => {
m.error('main')
console.log(`\n ${errorLog}failed to build main process`)
console.error(`\n${err}\n`)
process.exit(1)
})
pack(rendererConfig).then(result => {
results += result + '\n\n'
m.success('renderer')
}).catch(err => {
m.error('renderer')
console.log(`\n ${errorLog}failed to build renderer process`)
console.error(`\n${err}\n`)
process.exit(1)
})
}
function pack (config) {
return new Promise((resolve, reject) => {
webpack(config, (err, stats) => {
if (err) reject(err.stack || err)
else if (stats.hasErrors()) {
let err = ''
stats.toString({
chunks: false,
colors: true
})
.split(/\r?\n/)
.forEach(line => {
err += ` ${line}\n`
})
reject(err)
} else {
resolve(stats.toString({
chunks: false,
colors: true
}))
}
})
})
}
function web () {
del.sync(['dist/web/*', '!.gitkeep'])
webpack(webConfig, (err, stats) => {
if (err || stats.hasErrors()) console.log(err)
console.log(stats.toString({
chunks: false,
colors: true
}))
process.exit()
})
}
function greeting () {
const cols = process.stdout.columns
let text = ''
if (cols > 85) text = 'lets-build'
else if (cols > 60) text = 'lets-|build'
else text = false
if (text && !isCI) {
say(text, {
colors: ['yellow'],
font: 'simple3d',
space: false
})
} else console.log(chalk.yellow.bold('\n lets-build'))
console.log()
}

View File

@ -0,0 +1,40 @@
const hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true')
hotClient.subscribe(event => {
/**
* Reload browser when HTMLWebpackPlugin emits a new index.html
*
* Currently disabled until jantimon/html-webpack-plugin#680 is resolved.
* https://github.com/SimulatedGREG/electron-vue/issues/437
* https://github.com/jantimon/html-webpack-plugin/issues/680
*/
// if (event.action === 'reload') {
// window.location.reload()
// }
/**
* Notify `mainWindow` when `main` process is compiling,
* giving notice for an expected reload of the `electron` process
*/
if (event.action === 'compiling') {
document.body.innerHTML += `
<style>
#dev-client {
background: #4fc08d;
border-radius: 4px;
bottom: 20px;
box-shadow: 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12), 0 2px 4px -1px rgba(0, 0, 0, 0.3);
color: #fff;
font-family: 'Source Sans Pro', sans-serif;
left: 20px;
padding: 8px 12px;
position: absolute;
}
</style>
<div id="dev-client">
Compiling Main Process...
</div>
`
}
})

View File

@ -0,0 +1,178 @@
'use strict'
const chalk = require('chalk')
const electron = require('electron')
const path = require('path')
const { say } = require('cfonts')
const { spawn } = require('child_process')
const webpack = require('webpack')
const WebpackDevServer = require('webpack-dev-server')
const webpackHotMiddleware = require('webpack-hot-middleware')
const mainConfig = require('./webpack.main.config')
const rendererConfig = require('./webpack.renderer.config')
let electronProcess = null
let manualRestart = false
let hotMiddleware
function logStats (proc, data) {
let log = ''
log += chalk.yellow.bold(`${proc} Process ${new Array((19 - proc.length) + 1).join('-')}`)
log += '\n\n'
if (typeof data === 'object') {
data.toString({
colors: true,
chunks: false
}).split(/\r?\n/).forEach(line => {
log += ' ' + line + '\n'
})
} else {
log += ` ${data}\n`
}
log += '\n' + chalk.yellow.bold(`${new Array(28 + 1).join('-')}`) + '\n'
console.log(log)
}
function startRenderer () {
return new Promise((resolve, reject) => {
rendererConfig.entry.renderer = [path.join(__dirname, 'dev-client')].concat(rendererConfig.entry.renderer)
const compiler = webpack(rendererConfig)
hotMiddleware = webpackHotMiddleware(compiler, {
log: false,
heartbeat: 2500
})
compiler.plugin('compilation', compilation => {
compilation.plugin('html-webpack-plugin-after-emit', (data, cb) => {
hotMiddleware.publish({ action: 'reload' })
cb()
})
})
compiler.plugin('done', stats => {
logStats('Renderer', stats)
})
const server = new WebpackDevServer(
compiler,
{
contentBase: path.join(__dirname, '../'),
quiet: true,
before (app, ctx) {
app.use(hotMiddleware)
ctx.middleware.waitUntilValid(() => {
resolve()
})
}
}
)
server.listen(9080)
})
}
function startMain () {
return new Promise((resolve, reject) => {
mainConfig.entry.main = [path.join(__dirname, '../src/main/index.dev.js')].concat(mainConfig.entry.main)
const compiler = webpack(mainConfig)
compiler.plugin('watch-run', (compilation, done) => {
logStats('Main', chalk.white.bold('compiling...'))
hotMiddleware.publish({ action: 'compiling' })
done()
})
compiler.watch({}, (err, stats) => {
if (err) {
console.log(err)
return
}
logStats('Main', stats)
if (electronProcess && electronProcess.kill) {
manualRestart = true
process.kill(electronProcess.pid)
electronProcess = null
startElectron()
setTimeout(() => {
manualRestart = false
}, 5000)
}
resolve()
})
})
}
function startElectron () {
electronProcess = spawn(electron, ['--inspect=5858', '.'])
electronProcess.stdout.on('data', data => {
electronLog(data, 'blue')
})
electronProcess.stderr.on('data', data => {
electronLog(data, 'red')
})
electronProcess.on('close', () => {
if (!manualRestart) process.exit()
})
}
function electronLog (data, color) {
let log = ''
data = data.toString().split(/\r?\n/)
data.forEach(line => {
log += ` ${line}\n`
})
if (/[0-9A-z]+/.test(log)) {
console.log(
chalk[color].bold('┏ Electron -------------------') +
'\n\n' +
log +
chalk[color].bold('┗ ----------------------------') +
'\n'
)
}
}
function greeting () {
const cols = process.stdout.columns
let text = ''
if (cols > 104) text = 'electron-vue'
else if (cols > 76) text = 'electron-|vue'
else text = false
if (text) {
say(text, {
colors: ['yellow'],
font: 'simple3d',
space: false
})
} else console.log(chalk.yellow.bold('\n electron-vue'))
console.log(chalk.blue(' getting ready...') + '\n')
}
function init () {
greeting()
Promise.all([startRenderer(), startMain()])
.then(() => {
startElectron()
})
.catch(err => {
console.error(err)
})
}
init()

View File

@ -0,0 +1,83 @@
'use strict'
process.env.BABEL_ENV = 'main'
const path = require('path')
const { dependencies } = require('../package.json')
const webpack = require('webpack')
const BabiliWebpackPlugin = require('babili-webpack-plugin')
let mainConfig = {
entry: {
main: path.join(__dirname, '../src/main/index.js')
},
externals: [
...Object.keys(dependencies || {})
],
module: {
rules: [
{
test: /\.(js)$/,
enforce: 'pre',
exclude: /node_modules/,
use: {
loader: 'eslint-loader',
options: {
formatter: require('eslint-friendly-formatter')
}
}
},
{
test: /\.js$/,
use: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.node$/,
use: 'node-loader'
}
]
},
node: {
__dirname: process.env.NODE_ENV !== 'production',
__filename: process.env.NODE_ENV !== 'production'
},
output: {
filename: '[name].js',
libraryTarget: 'commonjs2',
path: path.join(__dirname, '../dist/electron')
},
plugins: [
new webpack.NoEmitOnErrorsPlugin()
],
resolve: {
extensions: ['.js', '.json', '.node']
},
target: 'electron-main'
}
/**
* Adjust mainConfig for development settings
*/
if (process.env.NODE_ENV !== 'production') {
mainConfig.plugins.push(
new webpack.DefinePlugin({
'__static': `"${path.join(__dirname, '../static').replace(/\\/g, '\\\\')}"`
})
)
}
/**
* Adjust mainConfig for production settings
*/
if (process.env.NODE_ENV === 'production') {
mainConfig.plugins.push(
new BabiliWebpackPlugin(),
new webpack.DefinePlugin({
'process.env.NODE_ENV': '"production"'
})
)
}
module.exports = mainConfig

View File

@ -0,0 +1,178 @@
'use strict'
process.env.BABEL_ENV = 'renderer'
const path = require('path')
const { dependencies } = require('../package.json')
const webpack = require('webpack')
const BabiliWebpackPlugin = require('babili-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
/**
* List of node_modules to include in webpack bundle
*
* Required for specific packages like Vue UI libraries
* that provide pure *.vue files that need compiling
* https://simulatedgreg.gitbooks.io/electron-vue/content/en/webpack-configurations.html#white-listing-externals
*/
let whiteListedModules = ['vue']
let rendererConfig = {
devtool: '#cheap-module-eval-source-map',
entry: {
renderer: path.join(__dirname, '../src/renderer/main.js')
},
externals: [
...Object.keys(dependencies || {}).filter(d => !whiteListedModules.includes(d))
],
module: {
rules: [
{
test: /\.(js|vue)$/,
enforce: 'pre',
exclude: /node_modules/,
use: {
loader: 'eslint-loader',
options: {
formatter: require('eslint-friendly-formatter')
}
}
},
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: 'css-loader'
})
},
{
test: /\.html$/,
use: 'vue-html-loader'
},
{
test: /\.js$/,
use: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.node$/,
use: 'node-loader'
},
{
test: /\.vue$/,
use: {
loader: 'vue-loader',
options: {
extractCSS: process.env.NODE_ENV === 'production',
loaders: {
sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax=1',
scss: 'vue-style-loader!css-loader!sass-loader'
}
}
}
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
use: {
loader: 'url-loader',
query: {
limit: 10000,
name: 'imgs/[name]--[folder].[ext]'
}
}
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: 'media/[name]--[folder].[ext]'
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
use: {
loader: 'url-loader',
query: {
limit: 10000,
name: 'fonts/[name]--[folder].[ext]'
}
}
}
]
},
node: {
__dirname: process.env.NODE_ENV !== 'production',
__filename: process.env.NODE_ENV !== 'production'
},
plugins: [
new ExtractTextPlugin('styles.css'),
new HtmlWebpackPlugin({
filename: 'index.html',
template: path.resolve(__dirname, '../src/index.ejs'),
minify: {
collapseWhitespace: true,
removeAttributeQuotes: true,
removeComments: true
},
nodeModules: process.env.NODE_ENV !== 'production'
? path.resolve(__dirname, '../node_modules')
: false
}),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin()
],
output: {
filename: '[name].js',
libraryTarget: 'commonjs2',
path: path.join(__dirname, '../dist/electron')
},
resolve: {
alias: {
'@': path.join(__dirname, '../src/renderer'),
'vue$': 'vue/dist/vue.esm.js'
},
extensions: ['.js', '.vue', '.json', '.css', '.node']
},
target: 'electron-renderer'
}
/**
* Adjust rendererConfig for development settings
*/
if (process.env.NODE_ENV !== 'production') {
rendererConfig.plugins.push(
new webpack.DefinePlugin({
'__static': `"${path.join(__dirname, '../static').replace(/\\/g, '\\\\')}"`
})
)
}
/**
* Adjust rendererConfig for production settings
*/
if (process.env.NODE_ENV === 'production') {
rendererConfig.devtool = ''
rendererConfig.plugins.push(
new BabiliWebpackPlugin(),
new CopyWebpackPlugin([
{
from: path.join(__dirname, '../static'),
to: path.join(__dirname, '../dist/electron/static'),
ignore: ['.*']
}
]),
new webpack.DefinePlugin({
'process.env.NODE_ENV': '"production"'
}),
new webpack.LoaderOptionsPlugin({
minimize: true
})
)
}
module.exports = rendererConfig

View File

@ -0,0 +1,139 @@
'use strict'
process.env.BABEL_ENV = 'web'
const path = require('path')
const webpack = require('webpack')
const BabiliWebpackPlugin = require('babili-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
let webConfig = {
devtool: '#cheap-module-eval-source-map',
entry: {
web: path.join(__dirname, '../src/renderer/main.js')
},
module: {
rules: [
{
test: /\.(js|vue)$/,
enforce: 'pre',
exclude: /node_modules/,
use: {
loader: 'eslint-loader',
options: {
formatter: require('eslint-friendly-formatter')
}
}
},
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: 'css-loader'
})
},
{
test: /\.html$/,
use: 'vue-html-loader'
},
{
test: /\.js$/,
use: 'babel-loader',
include: [ path.resolve(__dirname, '../src/renderer') ],
exclude: /node_modules/
},
{
test: /\.vue$/,
use: {
loader: 'vue-loader',
options: {
extractCSS: true,
loaders: {
sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax=1',
scss: 'vue-style-loader!css-loader!sass-loader'
}
}
}
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
use: {
loader: 'url-loader',
query: {
limit: 10000,
name: 'imgs/[name].[ext]'
}
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
use: {
loader: 'url-loader',
query: {
limit: 10000,
name: 'fonts/[name].[ext]'
}
}
}
]
},
plugins: [
new ExtractTextPlugin('styles.css'),
new HtmlWebpackPlugin({
filename: 'index.html',
template: path.resolve(__dirname, '../src/index.ejs'),
minify: {
collapseWhitespace: true,
removeAttributeQuotes: true,
removeComments: true
},
nodeModules: false
}),
new webpack.DefinePlugin({
'process.env.IS_WEB': 'true'
}),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin()
],
output: {
filename: '[name].js',
path: path.join(__dirname, '../dist/web')
},
resolve: {
alias: {
'@': path.join(__dirname, '../src/renderer'),
'vue$': 'vue/dist/vue.esm.js'
},
extensions: ['.js', '.vue', '.json', '.css']
},
target: 'web'
}
/**
* Adjust webConfig for production settings
*/
if (process.env.NODE_ENV === 'production') {
webConfig.devtool = ''
webConfig.plugins.push(
new BabiliWebpackPlugin(),
new CopyWebpackPlugin([
{
from: path.join(__dirname, '../static'),
to: path.join(__dirname, '../dist/web/static'),
ignore: ['.*']
}
]),
new webpack.DefinePlugin({
'process.env.NODE_ENV': '"production"'
}),
new webpack.LoaderOptionsPlugin({
minimize: true
})
)
}
module.exports = webConfig

0
.eslintignore 100644
View File

26
.eslintrc.js 100644
View File

@ -0,0 +1,26 @@
module.exports = {
root: true,
parser: 'babel-eslint',
parserOptions: {
sourceType: 'module'
},
env: {
browser: true,
node: true
},
extends: 'standard',
globals: {
__static: true
},
plugins: [
'html'
],
'rules': {
// allow paren-less arrow functions
'arrow-parens': 0,
// allow async-await
'generator-star-spacing': 0,
// allow debugger during development
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0
}
}

12
.gitignore vendored 100644
View File

@ -0,0 +1,12 @@
.DS_Store
dist/electron/*
dist/web/*
build/*
!build/icons
node_modules/
npm-debug.log
npm-debug.log.*
thumbs.db
!.gitkeep
package-lock.json
yarn.lock

View File

@ -0,0 +1,8 @@
{
"folders": [
{
"path": "./../"
},
],
"settings": {}
}

25
README.md 100644
View File

@ -0,0 +1,25 @@
# gearfit2-musicsync
> Transfer your Music to your Samsung GearFit2 easily via WiFi
#### Build Setup
``` bash
# install dependencies
npm install
# serve with hot reload at localhost:9080
npm run dev
# build electron application for production
npm run build
# lint all JS/Vue component files in `src/`
npm run lint
```
---
This project was generated with [electron-vue](https://github.com/SimulatedGREG/electron-vue)@[4c6ee7b](https://github.com/SimulatedGREG/electron-vue/tree/4c6ee7bf4f9b4aa647a22ec1c1ca29c2e59c3645) using [vue-cli](https://github.com/vuejs/vue-cli). Documentation about the original structure can be found [here](https://simulatedgreg.gitbooks.io/electron-vue/content/index.html).

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 KiB

0
dist/electron/.gitkeep vendored 100644
View File

0
dist/web/.gitkeep vendored 100644
View File

112
package.json 100644
View File

@ -0,0 +1,112 @@
{
"name": "gearfit2-musicsync",
"version": "0.0.0",
"author": "PHENOM <thephenom1811@gmail.com>",
"description": "Transfer your Music to your Samsung GearFit2 easily via WiFi",
"license": null,
"main": "./dist/electron/main.js",
"scripts": {
"build": "node .electron-vue/build.js && electron-builder",
"build:dir": "node .electron-vue/build.js && electron-builder --dir",
"build:clean": "cross-env BUILD_TARGET=clean node .electron-vue/build.js",
"build:web": "cross-env BUILD_TARGET=web node .electron-vue/build.js",
"dev": "node .electron-vue/dev-runner.js",
"lint": "eslint --ext .js,.vue -f ./node_modules/eslint-friendly-formatter src",
"lint:fix": "eslint --ext .js,.vue -f ./node_modules/eslint-friendly-formatter --fix src",
"pack": "npm run pack:main && npm run pack:renderer",
"pack:main": "cross-env NODE_ENV=production webpack --progress --colors --config .electron-vue/webpack.main.config.js",
"pack:renderer": "cross-env NODE_ENV=production webpack --progress --colors --config .electron-vue/webpack.renderer.config.js",
"postinstall": "npm run lint:fix"
},
"build": {
"productName": "gearfit2-musicsync",
"appId": "org.simulatedgreg.electron-vue",
"directories": {
"output": "build"
},
"files": [
"dist/electron/**/*"
],
"dmg": {
"contents": [
{
"x": 410,
"y": 150,
"type": "link",
"path": "/Applications"
},
{
"x": 130,
"y": 150,
"type": "file"
}
]
},
"mac": {
"icon": "build/icons/icon.icns"
},
"win": {
"icon": "build/icons/icon.ico"
},
"linux": {
"icon": "build/icons"
}
},
"dependencies": {
"axios": "^0.16.1",
"ipaddr": "0.0.9",
"material-design-icons": "^3.0.1",
"mdi": "^2.2.43",
"roboto-fontface": "^0.9.0",
"vue": "^2.3.3",
"vue-electron": "^1.0.6",
"vue-router": "^2.5.3",
"vue2-dropzone": "^3.2.2",
"vuetify": "^1.1.4",
"vuex": "^2.3.1"
},
"devDependencies": {
"babel-core": "^6.25.0",
"babel-loader": "^7.1.1",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-env": "^1.6.0",
"babel-preset-stage-0": "^6.24.1",
"babel-register": "^6.24.1",
"babili-webpack-plugin": "^0.1.2",
"cfonts": "^1.1.3",
"chalk": "^2.1.0",
"copy-webpack-plugin": "^4.0.1",
"cross-env": "^5.0.5",
"css-loader": "^0.28.4",
"del": "^3.0.0",
"devtron": "^1.4.0",
"electron": "^1.7.5",
"electron-debug": "^1.4.0",
"electron-devtools-installer": "^2.2.0",
"electron-builder": "^19.19.1",
"babel-eslint": "^7.2.3",
"eslint": "^4.4.1",
"eslint-friendly-formatter": "^3.0.0",
"eslint-loader": "^1.9.0",
"eslint-plugin-html": "^3.1.1",
"eslint-config-standard": "^10.2.1",
"eslint-plugin-import": "^2.7.0",
"eslint-plugin-node": "^5.1.1",
"eslint-plugin-promise": "^3.5.0",
"eslint-plugin-standard": "^3.0.1",
"extract-text-webpack-plugin": "^3.0.0",
"file-loader": "^0.11.2",
"html-webpack-plugin": "^2.30.1",
"multispinner": "^0.2.1",
"node-loader": "^0.6.0",
"style-loader": "^0.18.2",
"url-loader": "^0.5.9",
"vue-html-loader": "^1.2.4",
"vue-loader": "^13.0.5",
"vue-style-loader": "^3.0.1",
"vue-template-compiler": "^2.4.2",
"webpack": "^3.5.2",
"webpack-dev-server": "^2.7.1",
"webpack-hot-middleware": "^2.18.2"
}
}

22
src/index.ejs 100644
View File

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>gearfit2-musicsync</title>
<% if (htmlWebpackPlugin.options.nodeModules) { %>
<!-- Add `node_modules/` to global paths so `require` works properly in development -->
<script>
require('module').globalPaths.push('<%= htmlWebpackPlugin.options.nodeModules.replace(/\\/g, '\\\\') %>')
</script>
<% } %>
</head>
<body>
<div id="app"></div>
<!-- Set `__static` path to static files in production -->
<script>
if (process.env.NODE_ENV !== 'development') window.__static = require('path').join(__dirname, '/static').replace(/\\/g, '\\\\')
</script>
<!-- webpack builds are automatically injected -->
</body>
</html>

View File

@ -0,0 +1,27 @@
/**
* This file is used specifically and only for development. It installs
* `electron-debug` & `vue-devtools`. There shouldn't be any need to
* modify this file, but it can be used to extend your development
* environment.
*/
/* eslint-disable */
// Set environment for development
process.env.NODE_ENV = 'development'
// Install `electron-debug` with `devtron`
require('electron-debug')({ showDevTools: true })
// Install `vue-devtools`
require('electron').app.on('ready', () => {
let installExtension = require('electron-devtools-installer')
installExtension.default(installExtension.VUEJS_DEVTOOLS)
.then(() => {})
.catch(err => {
console.log('Unable to install `vue-devtools`: \n', err)
})
})
// Require `main` process to boot app
require('./index')

186
src/main/index.js 100644
View File

@ -0,0 +1,186 @@
'use strict'
import { app, BrowserWindow, ipcMain } from 'electron'
// const uuidv4 = require('uuid/v4')
const ipaddr = require('ipaddr.js')
/**
* Set `__static` path to static files in production
* https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-static-assets.html
*/
if (process.env.NODE_ENV !== 'development') {
global.__static = require('path').join(__dirname, '/static').replace(/\\/g, '\\\\')
}
let mainWindow
const winURL = process.env.NODE_ENV === 'development'
? `http://localhost:9080`
: `file://${__dirname}/index.html`
function createWindow () {
/**
* Initial window options
*/
mainWindow = new BrowserWindow({
height: 800,
minWidth: 320,
minHeight: 240,
hasShadow: true,
useContentSize: true,
width: 1280,
frame: false
})
mainWindow.loadURL(winURL)
mainWindow.show()
mainWindow.on('closed', () => {
// Close all connections gracefully
mainWindow = null
})
}
app.on('ready', createWindow)
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
if (mainWindow === null) {
createWindow()
}
})
const WebSocket = require('ws')
const wss = new WebSocket.Server({ port: 32000 })
wss.on('connection', (ws, req) => {
SendRequestSystemInfo(ws)
ws.on('message', (message) => {
/**
const jsonObj = JSON.parse(message)
var ip = ipaddr.parse(req.connection.remoteAddress)
jsonObj.sender = ip.toIPv4Address().toString()
*/
HandleMessages(ws, message)
})
})
function SendRequestSystemInfo (webSock) {
var jsonObj = { 'systemInfo': {} }
SendCommand(webSock, jsonObj)
}
function SendRequestMusicLibrary (webSock) {
var jsonObj = { 'musicLibrary': {} }
SendCommand(webSock, jsonObj)
}
/**
function SendReturnCodes (webSock) {
var jsonReturnCodesString = JSON.stringify(jsonReturnCodesObj)
webSock.send(jsonReturnCodesString)
jsonReturnCodesObj = { 'returnCodes': [] }
}
function AddToReturnCodes(jsonObj) {
jsonReturnCodesObj.returnCodes.push(jsonObj)
}
*/
function SendCommand (webSock, jsonObj) {
var newJsonObj = {'command': jsonObj}
var jsonReturnCodesString = JSON.stringify(newJsonObj)
console.log('Sending Command: %s', jsonReturnCodesString)
webSock.send(jsonReturnCodesString)
}
function HandleMessages (webSock, message) {
var messageJson = JSON.parse(message)
if (messageJson != null) {
if (messageJson.command != null) {
switch (true) {
case messageJson.command.hasOwnProperty('systemInfo'):
// AddToReturnCodes(ReturnSystemInfo(webSock))
break
case messageJson.command.hasOwnProperty('requestMusicLibrary'):
// ReturnMusicLibrary(webSock)
break
default:
alert('Unknown Command: ' + messageJson.command)
}
} else if (messageJson.returnCode != null) {
switch (true) {
case (messageJson.returnCode.hasOwnProperty('systemInfo')):
HandleSystemInfo(webSock, messageJson.returnCode.systemInfo)
break
case (messageJson.returnCode.hasOwnProperty('musicLibrary')):
HandleMusicLibrary(webSock, messageJson.returnCode.musicLibrary)
break
default:
alert('Unknown ReturnCode: ' + messageJson.returnCode)
}
}
}
}
function HandleSystemInfo (webSock, systemInfo) {
systemInfo.ip = ipaddr.parse(webSock._socket.remoteAddress).toIPv4Address().toString()
mainWindow.webContents.send('onSystemInfo', systemInfo)
}
function HandleMusicLibrary (webSock, musicLibrary) {
var parseIp = ipaddr.parse(webSock._socket.remoteAddress).toIPv4Address().toString()
var newMusicLib = {ip: parseIp, musicLibrary}
mainWindow.webContents.send('onMusicLibrary', newMusicLib)
}
ipcMain.on('disconnectDevice', (event, device) => {
var webSock = GetWebSocketByIp(device.ip)
if (webSock != null) {
webSock.close(1000, 'Removal request')
}
})
ipcMain.on('requestMusicLibrary', (event, device) => {
var webSock = GetWebSocketByIp(device.ip)
if (webSock != null) {
SendRequestMusicLibrary(webSock)
}
})
function GetWebSocketByIp (ip) {
const iterator = wss.clients.values()
for (let client of iterator) {
var clientIp = ipaddr.parse(client._socket.remoteAddress).toIPv4Address().toString()
if (clientIp === ip) {
return client
}
}
}
wss.on('close', () => {
console.log('disconnected')
})
/**
* Auto Updater
*
* Uncomment the following code below and install `electron-updater` to
* support auto updating. Code Signing with a valid certificate is required.
* https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-electron-builder.html#auto-updating
*/
/*
import { autoUpdater } from 'electron-updater'
autoUpdater.on('update-downloaded', () => {
autoUpdater.quitAndInstall()
})
app.on('ready', () => {
if (process.env.NODE_ENV === 'production') autoUpdater.checkForUpdates()
})
*/

View File

@ -0,0 +1,225 @@
<template>
<v-app dark>
<v-system-bar
style="-webkit-app-region: drag; -webkit-user-select: none;"
app
window
dark
>
<v-spacer></v-spacer>
<v-btn style="-webkit-app-region: no-drag" @click.stop="minimizeWindow()" small flat icon color="blue-grey">
<v-icon>remove</v-icon>
</v-btn>
<v-btn style="-webkit-app-region: no-drag" @click.stop="maximizeWindow()" small flat icon color="blue-grey">
<v-icon>check_box_outline_blank</v-icon>
</v-btn>
<v-btn style="-webkit-app-region: no-drag" @click.stop="exitWindow()" small flat icon color="blue-grey">
<v-icon>close</v-icon>
</v-btn>
</v-system-bar>
<v-navigation-drawer
v-model="drawer"
app
clipped
id="scroll-style"
>
<v-list dense>
<v-list-tile ripple v-for="page in pages" :key="page.text" @click.stop="gotoPage(page)">
<v-list-tile-action>
<v-icon>{{ page.icon }}</v-icon>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>
{{ page.text }}
</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
<v-divider></v-divider>
<v-subheader>Your music:</v-subheader>
<v-list-tile>
<v-list-tile-action>
<v-icon color="green">{{ pageMusicLibrary.icon }}</v-icon>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>{{ pageMusicLibrary.text }}</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
<v-list-tile v-for='device in devices' :key='device.ip' @click.stop='gotoMusicLibrary(device.ip)'>
<v-list-tile-action></v-list-tile-action>
<v-list-tile-action>
<v-icon color="pink">mdi-watch-variant</v-icon>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>{{ device.manufacturer }} {{ getGearAssets(device.model).name }}</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
</v-list>
</v-navigation-drawer>
<v-toolbar
color="light-green darken-2"
dense
clipped-left
app
>
<v-toolbar-side-icon @click.stop="drawer = !drawer"></v-toolbar-side-icon>
<v-icon class="mx-3">{{ currentPage.icon }}</v-icon>
<v-toolbar-title class="mr-5 align-center">
<span class="title">{{ currentPage.text }}</span>
</v-toolbar-title>
</v-toolbar>
<v-content>
<div class="scroll-container" id="scroll-style">
<v-container fluid>
<transition name="fade">
<router-view></router-view>
</transition>
</v-container>
</div>
</v-content>
<v-snackbar
v-model="newDevice.toast"
color = 'success'
>
{{ newDevice.manufacturer }} {{ newDevice.model }} successfully connected!
<v-btn dark flat @click.native="newDevice.toast = false">Close</v-btn>
</v-snackbar>
<v-footer app>
<v-btn flat @click.stop='openExternalSite("https://duckduckgo.com")'><v-icon left>get_app</v-icon>Get the App</v-btn>
<v-spacer></v-spacer>
<v-btn flat @click.stop='openExternalSite("https://phenomic.net")'>
by PHENOM
</v-btn>
</v-footer>
</v-app>
</template>
<script>
import router from './router'
import store from './store'
import { globalMethodsMixin } from './components/GlobalMethods.vue'
const { remote, ipcRenderer } = require('electron')
var TMP = { maximized: false }
export default {
name: 'gearfit2-musicsync',
mixins: [globalMethodsMixin],
data: () => ({
drawer: true,
pages: [
{ icon: 'home', text: 'Home', link: 'home' },
{ icon: 'settings_applications', text: 'Settings', link: 'settings' }
],
pageMusicLibrary: { icon: 'library_music', text: 'Music Library', link: 'musiclibrary' },
currentPage: { icon: 'home', text: 'Home', link: 'home' },
musicLibDrawerOpen: false,
newDevice: {toast: false}
}),
computed: {
devices () {
return store.state.Devices.devices
}
},
components: router,
methods: {
gotoPage (page) {
router.push(page.link)
this.currentPage = page
},
gotoMusicLibrary (deviceIp) {
router.push({ name: 'musiclibrary-page', query: { device: deviceIp } })
},
minimizeWindow () {
remote.BrowserWindow.getFocusedWindow().minimize()
},
maximizeWindow () {
var currentWindow = remote.BrowserWindow.getFocusedWindow()
currentWindow.on('maximize', () => {
TMP.maximized = true
})
currentWindow.on('unmaximize', () => {
TMP.maximized = false
})
if (TMP.maximized === true) {
TMP.maximized = false
currentWindow.unmaximize()
} else {
TMP.maximized = true
currentWindow.maximize()
}
},
exitWindow () {
remote.BrowserWindow.getFocusedWindow().close()
},
openExternalSite (site) {
remote.shell.openExternal(site)
}
},
mounted () {
ipcRenderer.on('onSystemInfo', (event, arg) => {
this.newDevice = {toast: true, manufacturer: arg.manufacturer, model: arg.model}
// Do some checks if the Device is already existant
if (store.getters.getDeviceByIp(arg.ip) != null) {
// Device already connected
} else {
store.commit('addDevice', arg)
}
})
ipcRenderer.on('onDeviceDisconnect', (event, arg) => {
})
}
}
</script>
<style>
html {
overflow-y: hidden;
}
.content {
max-height: 100vh;
}
.scroll-container {
height: 100%;
overflow-y: auto;
backface-visibility: hidden;
}
#scroll-style::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
border-radius: 10px;
background-color: #f5f5f5;
}
#scroll-style::-webkit-scrollbar {
width: 12px;
background-color: #f5f5f5;
}
#scroll-style::-webkit-scrollbar-thumb {
border-radius: 10px;
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
background-color: #555;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s ease;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
</style>

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB