Commit 9ffd12b5 authored by Benoit Lavenier's avatar Benoit Lavenier
Browse files

[enh] Manage URI in the main app.controller, instead of the csPlatform

[enh] BMA: can parse parse june:// URI
[enh] Better JShint reporter, when using 'npm run lint'
parent bacda093
Pipeline #9501 failed
......@@ -36,7 +36,7 @@ const gulp = require('gulp'),
argv = require('yargs').argv,
sriHash = require('gulp-sri-hash'),
sort = require('gulp-sort'),
gulpfile = this;
map = require('map-stream');
// Workaround because @ioni/v1-toolkit use gulp v3.9.2 instead of gulp v4
let jsonlint;
......@@ -62,7 +62,7 @@ const paths = {
ng_annotate_plugin: ['./www/plugins/*/**/*.js', '!./www/plugins/*/js/vendor/*.js']
};
const uglifyOptions = {
const uglifyBaseOptions = {
toplevel: true,
warnings: true,
mangle: {
......@@ -80,6 +80,13 @@ const uglifyOptions = {
max_line_len: 120000
}
};
const debugBaseOptions = {
title: 'Processing',
minimal: true,
showFiles: argv.debug || false,
showCount: argv.debug || false,
logger: m => log(colors.grey(m))
};
function appAndPluginWatch(done) {
......@@ -102,6 +109,15 @@ function appAndPluginWatch(done) {
if (done) done();
}
function appAndPluginClean() {
return del([
'./www/dist',
'./www/css/ionic.app*.css',
'./www/css/leaflet.app*.css'
]);
}
/**
* Generate App CSS (using SASS)
* @returns {*}
......@@ -157,8 +173,25 @@ function appConfig() {
.pipe(gulp.dest('www/js'));
}
function appAndPluginLint(done) {
log(colors.green('Linting JS files...'));
// Copy Js (and remove unused code)
return gulp.src(paths.ng_annotate.concat(paths.ng_annotate_plugin))
.pipe(debug({...debugBaseOptions, title: 'Linting'}))
.pipe(jshint())
.pipe(jshint.reporter(require('jshint-stylish')))
.pipe(map( (file, cb) => {
if (!file.jshint.success) {
console.error('jshint failed');
process.exit(1);
}
}))
.on('end', done);
}
function appNgTemplate() {
log(colors.green('Building App template file...'));
log(colors.green('Building template file...'));
return gulp.src(paths.templatecache)
.pipe(sort())
......@@ -188,7 +221,7 @@ function appNgAnnotate(event) {
}
function appNgTranslate() {
log(colors.green('Building App translation file...'));
log(colors.green('Building translation file...'));
return gulp.src('www/i18n/locale-*.json')
.pipe(jsonlint())
......@@ -281,7 +314,7 @@ function pluginSass() {
return merge(
// Copy plugins CSS
gulp.src(paths.css_plugin, {read: false})
gulp.src(paths.css_plugin)
.pipe(gulp.dest('www/dist/dist_css/plugins')),
// Leaflet images
......@@ -481,8 +514,8 @@ function webPluginNgTemplate() {
return gulp.src(targetPath + '/plugins/**/*.html')
.pipe(sort())
.pipe(templateCache({
standalone:true,
module:"cesium.plugins.templates",
standalone: true,
module: "cesium.plugins.templates",
root: "plugins/"
}))
.pipe(gulp.dest(targetPath + '/dist/dist_js/plugins'));
......@@ -514,7 +547,7 @@ function webUglify() {
// Process JS
.pipe(jsFilter)
.pipe(uglify(uglifyOptions)) // Minify javascript files
.pipe(uglify(uglifyBaseOptions)) // Minify javascript files
.pipe(jsFilter.restore)
// Process CSS
......@@ -585,7 +618,7 @@ function webApiUglify() {
// Process JS
.pipe(jsFilter)
.pipe(uglify(uglifyOptions)) // Minify any javascript sources
.pipe(uglify(uglifyBaseOptions)) // Minify any javascript sources
.pipe(jsFilter.restore)
// Process CSS
......@@ -856,8 +889,8 @@ function cdvAddPlatformToBodyTag() {
}
}
function cdvCopyFiles() {
log(colors.green('Copying files... '));
function cdvNgAnnotate() {
log(colors.green('Building JS files... '));
const projectRoot = argv.root || '.';
const platform = argv.platform || 'android';
......@@ -882,17 +915,17 @@ function cdvCopyFiles() {
gulp.src(wwwPath + '/plugins/**/*.js')
.pipe(ngAnnotate({single_quotes: true}))
.pipe(gulp.dest(wwwPath + '/dist/dist_js/plugins')),
/*
// Copy plugin CSS
gulp.src(wwwPath + '/plugins/*/css/**/*.css')
gulp.src(wwwPath + '/plugins/!*!/css/!**!/!*.css')
.pipe(gulp.dest(wwwPath + '/dist/dist_css/plugins')),
// Copy Leaflet images
pluginLeafletImages(wwwPath + '/img'),
// Copy Leaflet CSS
gulp.src('./www/css/**/leaflet.*')
.pipe(gulp.dest(wwwPath + '/css'))
gulp.src('./www/css/!**!/leaflet.*')
.pipe(gulp.dest(wwwPath + '/css'))*/
);
}
......@@ -1099,7 +1132,7 @@ function cdvUglify() {
const jsLibFilter = filter(['*/lib/**/*.js', '*/js/vendor/**/*.js'], {restore: true}); // External libs only
const cssFilter = filter("**/*.css", {restore: true});
const cdvUglifyOptions = {
...uglifyOptions,
...uglifyBaseOptions,
ecma: '5'
};
const debugOptions = {
......@@ -1238,11 +1271,12 @@ function cdvAndroidManifest() {
const projectRoot = argv.root || '.';
const platform = argv.platform || 'android';
if (platform !== 'android') return Promise.resolve(); // Skip
const srcMainPath = path.join(projectRoot, 'platforms', platform, 'app', 'src', 'main');
const androidManifestFile = path.join(srcMainPath, 'AndroidManifest.xml');
log(colors.green(' Updating Android manifest... ') + colors.grey(androidManifestFile));
log(colors.green('Patch Android manifest... ') + colors.grey(androidManifestFile));
if (!fs.existsSync(androidManifestFile)) {
throw Error("Missing required file " + androidManifestFile);
......@@ -1276,6 +1310,8 @@ function cdvAndroidCheckSigning() {
const projectRoot = argv.root || '.';
const platform = argv.platform || 'android';
if (platform !== 'android') return Promise.resolve(); // Skip
const targetPath = path.join(projectRoot, 'platforms', platform);
const signingFile = path.join(targetPath, 'release-signing.properties');
......@@ -1288,28 +1324,18 @@ function cdvAndroidCheckSigning() {
return Promise.resolve();
}
function cdvAfterPrepare(done, projectRoot, platform) {
function cdvAsHook(wrapper) {
projectRoot = (typeof projectRoot === 'string' && projectRoot) || argv.root || '.';
platform = ((typeof platform === 'string' && platform) || argv.platform || 'android').toLowerCase();
return (done, projectRoot, platform) => {
projectRoot = (typeof projectRoot === 'string' && projectRoot) || argv.root || '.';
platform = ((typeof platform === 'string' && platform) || argv.platform || 'android').toLowerCase();
// Override arguments, to pass it to other tasks
argv.root = projectRoot;
argv.platform = platform;
// Override arguments, to pass it to other tasks
argv.root = projectRoot;
argv.platform = platform;
let wrapper = gulp.series(
gulp.parallel(cdvCopyFiles, cdvAddPlatformToBodyTag),
cdvRemoveCode,
gulp.parallel(cdvNgTemplate, cdvNgTranslate),
cdvUglify,
gulp.parallel(cdvCleanUnusedDirectories,cdvCopyBuildFiles)
);
if (platform === 'android') {
wrapper = gulp.series(wrapper, cdvAndroidManifest, cdvAndroidCheckSigning);
wrapper(done);
}
wrapper(done);
}
function help() {
......@@ -1372,15 +1398,6 @@ const webExtBuild = gulp.series(
);
exports.cdvRemoveCode = cdvRemoveCode;
exports.cdvNgTemplate = cdvNgTemplate;
exports.cdvNgTranslate = cdvNgTranslate;
exports.cdvUglify = cdvUglify;
exports.cdvCleanUnusedDirectories = cdvCleanUnusedDirectories;
exports.cdvCopyBuildFiles = cdvCopyBuildFiles;
exports.cdvAndroidManifest = cdvAndroidManifest;
exports.cdvAndroidCheckSigning = cdvAndroidCheckSigning;
exports.cdvAfterPrepare = cdvAfterPrepare;
/* --------------------------------------------------------------------------
-- Define public tasks
......@@ -1392,20 +1409,36 @@ exports.license = appLicense;
exports.sass = appAndPluginSass;
exports.translate = translate;
exports.template = template;
exports.annotate = appNgAnnotate;
exports.clean = appAndPluginClean;
exports.lint = appAndPluginLint;
exports.annotate = gulp.series(appNgAnnotate, pluginNgAnnotate);
exports.watch = appAndPluginWatch;
exports.build = build;
// Web
exports.webCompile = webCompile;
exports.webBuild = webBuild;
exports['build:web'] = exports.webBuild; // Alias
// Web extension
exports.webExtClean = webExtClean;
exports.webExtCompile = webExtCompile;
exports.webExtBuild = webExtBuild;
exports.webExtCopyFiles = webExtCopyFiles;
exports['build:webExt'] = exports.webBuild; // Alias
// Cordova (hooks)
const cdvAfterPrepare = gulp.series(
gulp.parallel(cdvNgAnnotate, cdvAddPlatformToBodyTag),
cdvRemoveCode,
gulp.parallel(cdvNgTemplate, cdvNgTranslate),
cdvUglify,
gulp.parallel(cdvCleanUnusedDirectories, cdvCopyBuildFiles),
// Android tasks
gulp.parallel(cdvAndroidManifest, cdvAndroidCheckSigning),
);
exports.cdvAfterPrepare = cdvAsHook(cdvAfterPrepare);
exports.default = gulp.series(appConfig, build);
exports.serveBefore = gulp.series(build, appAndPluginWatch);
exports['ionic:serve:before'] = exports.serveBefore; // Alias need need by @ionic/cli
......@@ -12,7 +12,7 @@
"scripts": {
"clean": "trash www/dist/** dist/web/* dist/desktop/**/*.deb platforms/android/**/*.apk",
"postinstall": "node scripts/node/postinstall.js",
"lint": "node scripts/node/jshint.js",
"lint": "gulp lint",
"install-platforms": "ionic cordova prepare",
"start": "ionic serve",
"start:webExt": "gulp webExtCompile && web-ext run --source-dir ./dist/web/ext/",
......@@ -151,8 +151,10 @@
"gulp-useref": "^4.0.1",
"gulp-zip": "^5.0.2",
"ionic-plugin-keyboard": "^2.2.1",
"jshint": "^2.10.3",
"jshint": "^2.12.0",
"jshint-stylish": "^2.2.1",
"lazypipe": "^1.0.2",
"map-stream": "0.0.7",
"merge2": "^1.3.0",
"mv": "^2.1.1",
"node-sass": "^4.14.1",
......
#!/usr/bin/env node
const log = require('fancy-log'),
const gulp = require('gulp'),
path = require("path"),
colors = require('ansi-colors'),
jshint = require('../node/jshint-utils');
jshint = require('../node/jshint-utils'),
log = require('fancy-log');
module.exports = function(context) {
const now = Date.now();
......@@ -10,10 +12,13 @@ module.exports = function(context) {
const projectRoot = context && context.opts && context.opts.projectRoot || '.';
const platforms = context && context.opts && context.opts.platforms || ['android'];
if (!projectRoot || !platforms) return; // Skip
const gulpFile = require(path.join(projectRoot, 'gulpfile'));
if (!projectRoot || !platforms || !gulpFile) return; // Skip
// Run JS Lint
return jshint.validate(projectRoot)
return jshint.validate(projectRoot) // new Promise(done => gulpFile.lint(done))
.then(() => {
log(colors.grey("Hook 'before_prepare' finished in " + (Date.now() - now) + 'ms'));
});
......
......@@ -241,12 +241,6 @@ $screen-menu: $screen-sm;
}
}
@media screen and (max-width: $screen-sm-max) {
body {
cursor: url('http://ionicframework.com/img/finger.png'), auto;
}
}
@media screen and (min-width: $screen-md) {
body {
cursor: inherit;
......
......@@ -120,8 +120,8 @@ angular.module("cesium.config", [])
}
},
"version": "1.6.7",
"build": "2020-05-06T09:07:27.415Z",
"build": "2020-08-11T08:40:38.369Z",
"newIssueUrl": "https://git.duniter.org/clients/cesium-grp/cesium/issues/new"
})
;
;
\ No newline at end of file
......@@ -67,81 +67,6 @@ function AppController($scope, $rootScope, $state, $ionicSideMenuDelegate, $q, $
.then(UIUtils.loading.hide);
};
// removeIf(no-device)
////////////////////////////////////////
// Device only methods
// (code removed when NO device)
////////////////////////////////////////
$scope.scanQrCodeAndGo = function() {
if (!Device.barcode.enable) return;
// Run scan cordova plugin, on device
return Device.barcode.scan()
.then(function(data) {
if (!data) return;
// Try to parse as an URI
return BMA.uri.parse(data)
.then(function(res){
if (!res || !res.pubkey) throw {message: 'ERROR.SCAN_UNKNOWN_FORMAT'};
// If pubkey: open the identity
return $state.go('app.wot_identity', {
pubkey: res.pubkey,
node: res.host ? res.host: null}
);
})
// Not an URI: try WIF or EWIF format
.catch(function(err) {
console.debug("[app] Scan data is not an URI (get error: " + (err && err.message || err) + "). Trying to decode as a WIF or EWIF format...");
// Try to read as WIF format
return csCrypto.keyfile.parseData(data)
.then(function(keypair) {
if (!keypair || !keypair.signPk || !keypair.signSk) throw err; // rethrow the first error (e.g. Bad URI)
var pubkey = CryptoUtils.base58.encode(keypair.signPk);
console.debug("[app] Detected WIF/EWIF format. Will login to wallet {" + pubkey.substring(0, 8) + "}");
// Create a new wallet (if default wallet is already used)
var wallet = !csWallet.isLogin() ? csWallet : csWallet.children.create({store: false});
// Login using keypair
return wallet.login({
silent: true,
forceAuth: true,
minData: false,
authData: {
pubkey: pubkey,
keypair: keypair
}
})
.then(function () {
// Open transfer all wallet
$ionicHistory.nextViewOptions({
historyRoot: true
});
return $state.go('app.new_transfer', {
all: true, // transfer all sources
wallet: !wallet.isDefault() ? wallet.id : undefined
});
});
})
// Unknown format (nor URI, nor WIF/EWIF)
.catch(UIUtils.onError('ERROR.SCAN_UNKNOWN_FORMAT'));
});
})
.catch(UIUtils.onError('ERROR.SCAN_FAILED'));
};
////////////////////////////////////////
// End of device only methods
////////////////////////////////////////
// endRemoveIf(no-device)
////////////////////////////////////////
// Show Help tour
////////////////////////////////////////
......@@ -465,6 +390,83 @@ function AppController($scope, $rootScope, $state, $ionicSideMenuDelegate, $q, $
return false;
};
/**
* Parse an external URI (see g1lien), and open the expected state
* @param uri
* @returns {*}
*/
$scope.handleUri = function(uri) {
if (!uri) return $q.when(); // Skip
console.info('[app] Parsing external uri: ', uri);
var fromHomeState = $state.current && $state.current.name === 'app.home';
// Parse the URI
return BMA.uri.parse(uri)
.then(function(res) {
if (!res) throw {message: 'ERROR.UNKNOWN_URI_FORMAT'}; // Continue
if (res.pubkey) {
$state.go('app.wot_identity',
angular.merge({
pubkey: res.pubkey,
action: res.params && res.params.amount ? 'transfer' : undefined
}, res.params),
{reload: true});
}
else if (res.uid) {
return $state.go('app.wot_identity_uid',
angular.merge({
uid: res.uid,
action: res.params && res.params.amount ? 'transfer' : undefined
}, res.params),
{reload: true});
}
else if (angular.isDefined(res.block)) {
return $state.go('app.view_block',
angular.merge(res.block, res.params),
{reload: true});
}
// Default: wot lookup
else {
console.warn('[app] TODO implement state redirection from URI result: ', res, uri);
return $state.go('app.wot_lookup.tab_search',
{q: uri},
{reload: true});
}
})
// After state change
.then(function() {
if (fromHomeState) {
// Wait 500ms, then remove /app/home?uri from the history
// to make sure the back button will work fine
return $timeout(function () {
if ($ionicHistory.backView()) $ionicHistory.removeBackView();
}, 500);
}
})
.catch(function(err) {
console.error("[home] Error while handle uri {" + uri + "': ", err);
return UIUtils.onError(uri)(err);
});
};
$scope.registerProtocolHandlers = function() {
var protocols = ['web+june', /*'june' - NOT yet accepted by web browser */];
_.each(protocols, function(protocol) {
console.debug("[app] Registering protocol '%s'...".format(protocol));
try {
navigator.registerProtocolHandler(protocol, "#/app/home?uri=%s", "Cesium");
}
catch(err) {
console.error("[app] Error while registering protocol '%s'".format(protocol), err);
}
});
};
////////////////////////////////////////
// Layout Methods
////////////////////////////////////////
......@@ -505,8 +507,114 @@ function AppController($scope, $rootScope, $state, $ionicSideMenuDelegate, $q, $
UIUtils.screen.fullscreen.toggleAll();
};
// removeIf(no-device)
////////////////////////////////////////
// Device only methods
// (code removed when NO device)
////////////////////////////////////////
$scope.scanQrCodeAndGo = function() {
if (!Device.barcode.enable) return;
// Run scan cordova plugin, on device
return Device.barcode.scan()
.then(function(data) {
if (!data) return;
// Try to parse as an URI
return BMA.uri.parse(data)
.then(function(res){
if (!res || !res.pubkey) throw {message: 'ERROR.SCAN_UNKNOWN_FORMAT'};
// If pubkey: open the identity
return $state.go('app.wot_identity', {
pubkey: res.pubkey,
node: res.host ? res.host: null}
);
})
// Not an URI: try WIF or EWIF format
.catch(function(err) {
console.debug("[app] Scan data is not an URI (get error: " + (err && err.message || err) + "). Trying to decode as a WIF or EWIF format...");
// Try to read as WIF format
return csCrypto.keyfile.parseData(data)
.then(function(keypair) {
if (!keypair || !keypair.signPk || !keypair.signSk) throw err; // rethrow the first error (e.g. Bad URI)
var pubkey = CryptoUtils.base58.encode(keypair.signPk);
console.debug("[app] Detected WIF/EWIF format. Will login to wallet {" + pubkey.substring(0, 8) + "}");
// Create a new wallet (if default wallet is already used)
var wallet = !csWallet.isLogin() ? csWallet : csWallet.children.create({store: false});
// Login using keypair
return wallet.login({
silent: true,
forceAuth: true,
minData: false,
authData: {
pubkey: pubkey,
keypair: keypair
}
})
.then(function () {
// Open transfer all wallet
$ionicHistory.nextViewOptions({
historyRoot: true
});
return $state.go('app.new_transfer', {
all: true, // transfer all sources
wallet: !wallet.isDefault() ? wallet.id : undefined
});
});
})
// Unknown format (nor URI, nor WIF/EWIF)
.catch(UIUtils.onError('ERROR.SCAN_UNKNOWN_FORMAT'));
});
})
.catch(UIUtils.onError('ERROR.SCAN_FAILED'));
};
/**
* Process launch intent, as it could have been triggered BEFORE addListeners()
* @returns {*}
*/
$scope.processLaunchUri = function() {
return Device.intent.last()
.then(function(intent) {
if (intent) {
Device.intent.clear();
return $scope.handleUri(intent);
}
});
};
// Listen for new intent
Device.api.intent.on.new($scope, $scope.handleUri);
$scope.processLaunchUri();
////////////////////////////////////////
// End of device only methods
////////////////////////////////////////
// endRemoveIf(no-device)
// removeIf(device)
////////////////////////////////////////