1
0
Fork 0
mirror of https://github.com/betaflight/betaflight-configurator.git synced 2025-07-20 06:45:12 +03:00

Merge pull request #696 from sebsx/add-native-apps-via-nwjs

Add native apps build via nwjs
This commit is contained in:
Michael Keller 2017-11-05 07:13:55 +13:00 committed by GitHub
commit 01c0aaac0f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 4583 additions and 2 deletions

6
.gitignore vendored
View file

@ -3,4 +3,8 @@ nbproject/
.idea .idea
.project .project
.settings/ .settings/
node_modules/
npm-debug.log
cache/
apps/
dist/

View file

@ -42,6 +42,24 @@ Please note - the application will automatically update itself when new versions
You can find the Betaflight Configurator icon in your application tab "Apps" You can find the Betaflight Configurator icon in your application tab "Apps"
## Native app build via NW.js
Linux build is disabled currently because of unmet dependecies with some distros, it can be enabled in the `gulpfile.js`.
### Development
1. Install node.js
2. Change to project folder and run `npm install`
3. Run `npm start`
### App build and release
The tasks are defined in `gulpfile.js` and can be run either via `gulp task-name` (if the command is in PATH or via `../node_modules/gulp/bin/gulp.js task-name':
* **dist** copies all the JS and CSS files in the `./dist` folder
* **apps** builds the apps in the `./apps` folder
* **release** zips up the apps into individual archives in the `./apps` folder. Running this task on macOS or Linux requires Wine, since it's needed to set the icon for the Windows app.
## Notes ## Notes
### WebGL ### WebGL

242
gulpfile.js Normal file
View file

@ -0,0 +1,242 @@
'use strict';
var child_process = require('child_process');
var fs = require('fs');
var path = require('path');
var archiver = require('archiver');
var del = require('del');
var NwBuilder = require('nw-builder');
var gulp = require('gulp');
var concat = require('gulp-concat');
var runSequence = require('run-sequence');
var distDir = './dist/';
var appsDir = './apps/';
function get_task_name(key) {
return 'build-' + key.replace(/([A-Z])/g, function ($1) { return "-" + $1.toLowerCase(); });
}
gulp.task('clean', function () { return del(['./dist/**'], { force: true }); });
// Real work for dist task. Done in another task to call it via
// run-sequence.
gulp.task('dist-build', [], function () {
var distSources = [
// CSS files
'./main.css',
'./tabs/power.css',
'./tabs/firmware_flasher.css',
'./tabs/onboard_logging.css',
'./tabs/receiver.css',
'./tabs/cli.css',
'./tabs/servos.css',
'./tabs/adjustments.css',
'./tabs/configuration.css',
'./tabs/auxiliary.css',
'./tabs/pid_tuning.css',
'./tabs/transponder.css',
'./tabs/gps.css',
'./tabs/led_strip.css',
'./tabs/sensors.css',
'./tabs/osd.css',
'./tabs/motors.css',
'./tabs/receiver_msp.css',
'./tabs/logging.css',
'./tabs/landing.css',
'./tabs/setup_osd.css',
'./tabs/help.css',
'./tabs/failsafe.css',
'./tabs/ports.css',
'./tabs/setup.css',
'./css/opensans_webfontkit/fonts.css',
'./css/dropdown-lists/css/style_lists.css',
'./css/font-awesome/css/font-awesome.min.css',
'./js/libraries/flightindicators.css',
'./js/libraries/jbox/jBox.css',
'./js/libraries/jbox/themes/NoticeBorder.css',
'./js/libraries/jbox/themes/ModalBorder.css',
'./js/libraries/jbox/themes/TooltipDark.css',
'./js/libraries/jbox/themes/TooltipBorder.css',
'./js/libraries/jquery.nouislider.pips.min.css',
'./js/libraries/switchery/switchery.css',
'./js/libraries/jquery.nouislider.min.css',
'./node_modules/jquery-ui-npm/jquery-ui.min.css',
'./node_modules/jquery-ui-npm/jquery-ui.theme.min.css',
'./node_modules/jquery-ui-npm/jquery-ui.structure.min.css',
// JavaScript
'./js/libraries/q.js',
'./js/libraries/jquery-2.1.4.min.js',
'./js/libraries/jquery-ui-1.11.4.min.js',
'./js/libraries/d3.min.js',
'./js/libraries/jquery.nouislider.all.min.js',
'./js/libraries/three/three.min.js',
'./js/libraries/three/Projector.js',
'./js/libraries/three/CanvasRenderer.js',
'./js/libraries/jquery.flightindicators.js',
'./js/libraries/semver.js',
'./js/libraries/jbox/jBox.min.js',
'./js/libraries/switchery/switchery.js',
'./js/libraries/bluebird.min.js',
'./js/libraries/jquery.ba-throttle-debounce.min.js',
'./js/libraries/inflection.min.js',
'./js/injected_methods.js',
'./js/data_storage.js',
'./js/workers/hex_parser.js',
'./js/fc.js',
'./js/port_handler.js',
'./js/port_usage.js',
'./js/serial.js',
'./js/gui.js',
'./js/huffman.js',
'./js/default_huffman_tree.js',
'./js/model.js',
'./js/serial_backend.js',
'./js/msp/MSPCodes.js',
'./js/msp.js',
'./js/msp/MSPHelper.js',
'./js/backup_restore.js',
'./js/peripherals.js',
'./js/protocols/stm32.js',
'./js/protocols/stm32usbdfu.js',
'./js/localization.js',
'./js/boards.js',
'./js/RateCurve.js',
'./js/Features.js',
'./js/Beepers.js',
'./tabs/adjustments.js',
'./tabs/auxiliary.js',
'./tabs/cli.js',
'./tabs/configuration.js',
'./tabs/failsafe.js',
'./tabs/firmware_flasher.js',
'./tabs/gps.js',
'./tabs/help.js',
'./tabs/landing.js',
'./tabs/led_strip.js',
'./tabs/logging.js',
'./tabs/map.js',
'./tabs/motors.js',
'./tabs/onboard_logging.js',
'./tabs/osd.js',
'./tabs/pid_tuning.js',
'./tabs/ports.js',
'./tabs/power.js',
'./tabs/receiver.js',
'./tabs/receiver_msp.js',
'./tabs/sensors.js',
'./tabs/servos.js',
'./tabs/setup.js',
'./tabs/setup_osd.js',
'./tabs/transponder.js',
'./main.js',
// everything else
'./package.json', // For NW.js
'./manifest.json', // For Chrome app
'./eventPage.js',
'./*.html',
'./tabs/*.html',
'./images/**/*',
'./_locales/**/*',
'./css/font-awesome/fonts/*',
'./css/opensans_webfontkit/*.{eot,svg,ttf,woff,woff2}',
'./resources/*.json',
'./resources/models/*',
'./resources/osd/*.mcm',
'./resources/motor_order/*.svg',
];
return gulp.src(distSources, { base: '.' })
.pipe(gulp.dest(distDir));
});
gulp.task('dist', function () {
return runSequence('clean', 'dist-build');
});
// Create app directories in ./apps
gulp.task('apps', ['dist'], function (done) {
var builder = new NwBuilder({
files: './dist/**/*',
buildDir: appsDir,
platforms: ['osx64', 'win32'], // 'linux64' not working currently.
flavor: 'normal',
macIcns: './images/bf_icon.icns',
macPlist: { 'CFBundleDisplayName': 'Betaflight Configurator'},
winIco: './images/bf_icon.ico',
});
builder.on('log', console.log);
builder.build(function (err) {
if (err) {
console.log("Error building NW apps:" + err);
done();
return;
}
// Package apps as .zip files
done();
});
});
function get_release_filename(platform, ext) {
var pkg = require('./package.json');
return 'Betaflight-Configurator_' + platform + '_' + pkg.version + '.' + ext;
}
gulp.task('release-windows', function () {
var pkg = require('./package.json');
var src = path.join(appsDir, pkg.name, 'win32');
var output = fs.createWriteStream(path.join(appsDir, get_release_filename('win32', 'zip')));
var archive = archiver('zip', {
zlib: { level: 9 }
});
archive.on('warning', function (err) { throw err; });
archive.on('error', function (err) { throw err; });
archive.pipe(output);
archive.directory(src, 'Betaflight Configurator');
return archive.finalize();
});
gulp.task('release-linux', function () {
var pkg = require('./package.json');
var src = path.join(appsDir, pkg.name, 'linux64');
var output = fs.createWriteStream(path.join(appsDir, get_release_filename('linux64', 'zip')));
var archive = archiver('zip', {
zlib: { level: 9 }
});
archive.on('warning', function (err) { throw err; });
archive.on('error', function (err) { throw err; });
archive.pipe(output);
archive.directory(src, 'Betaflight Configurator');
return archive.finalize();
});
gulp.task('release-macos', function () {
var pkg = require('./package.json');
var src = path.join(appsDir, pkg.name, 'osx64', pkg.name + '.app');
// Check if we want to sign the .app bundle
if (process.env.CODESIGN_IDENTITY) {
var sign_cmd = 'codesign --verbose --force --sign "' + process.env.CODESIGN_IDENTITY + '" ' + src;
child_process.execSync(sign_cmd);
}
var output = fs.createWriteStream(path.join(appsDir, get_release_filename('macOS', 'zip')));
var archive = archiver('zip', {
zlib: { level: 9 }
});
archive.on('warning', function (err) { throw err; });
archive.on('error', function (err) { throw err; });
archive.pipe(output);
console.log("Archiving MacOS app at " + src);
archive.directory(src, 'Betaflight Configurator.app');
return archive.finalize();
});
// Create distributable .zip files in ./apps
gulp.task('release', function () {
// TODO: Linux
return runSequence('apps', 'release-macos', 'release-windows');
});
gulp.task('default', ['apps']);

BIN
images/bf_icon.icns Normal file

Binary file not shown.

BIN
images/bf_icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

4273
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

38
package.json Normal file
View file

@ -0,0 +1,38 @@
{
"name": "betaflight-configurator",
"description": "Betaflight Configurator",
"version": "3.2.2",
"main": "main.html",
"default_locale": "en",
"scripts": {
"start": "node_modules/gulp/bin/gulp.js dist && node_modules/nw/bin/nw ."
},
"window": {
"title": "Betaflight Configurator",
"icon": "images/inav_icon_128.png",
"toolbar": true,
"width": 1280,
"height": 800
},
"repository": {
"type": "git",
"url": "github.com/betaflight/betaflight-configurator"
},
"author": "iNavFlight",
"license": "GPL-3.0",
"dependencies": {
"archiver": "^2.0.3",
"bluebird": "3.4.1",
"del": "^3.0.0",
"gulp": "~3.9.1",
"gulp-concat": "~2.6.1",
"inflection": "1.12.0",
"jquery": "2.1.4",
"jquery-ui-npm": "1.12.0",
"nw": "^0.25.4-sdk",
"nw-builder": "^3.4.1",
"run-sequence": "^2.2.0",
"temp": "^0.8.3",
"three": "0.72.0"
}
}

View file

@ -1505,6 +1505,9 @@ TABS.osd.initialize = function (callback) {
ctx.drawImage(img, i*12, 0); ctx.drawImage(img, i*12, 0);
} }
field.preview_img.src = canvas.toDataURL('image/png'); field.preview_img.src = canvas.toDataURL('image/png');
// Required for NW.js - Otherwise the <img /> will
// consume drag/drop events.
field.preview_img.style.pointerEvents = 'none';
} }
var centerishPosition = 194; var centerishPosition = 194;
// artificial horizon // artificial horizon
@ -1548,6 +1551,9 @@ TABS.osd.initialize = function (callback) {
.on('drop', OSD.GUI.preview.onDrop) .on('drop', OSD.GUI.preview.onDrop)
.data('field', field) .data('field', field)
.data('position', i); .data('position', i);
// Required for NW.js - Otherwise the <img /> will
// consume drag/drop events.
$img.find('img').css('pointer-events', 'none');
if (field && field.positionable) { if (field && field.positionable) {
$img $img
.addClass('field-'+field.index) .addClass('field-'+field.index)