Correct merge conflicts to pull from master
29
.circleci/config.yml
Normal file
@ -0,0 +1,29 @@
|
||||
# Javascript Node CircleCI 2.0 configuration file
|
||||
# Check https://circleci.com/docs/2.0/language-javascript/ for more details
|
||||
version: 2
|
||||
jobs:
|
||||
build-and-test:
|
||||
docker:
|
||||
- image: circleci/node:8.10-browsers
|
||||
working_directory: ~/insight
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
# Download and cache dependencies
|
||||
- restore_cache:
|
||||
keys:
|
||||
- dependency-cache-{{ checksum "package.json" }}
|
||||
- run: npm install
|
||||
- save_cache:
|
||||
paths:
|
||||
- node_modules
|
||||
key: dependency-cache-{{ checksum "package.json" }}
|
||||
|
||||
# run tests
|
||||
- run: npm run test:ci
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
build_and_test:
|
||||
jobs:
|
||||
- build-and-test
|
||||
29
.gitignore
vendored
@ -1,31 +1,6 @@
|
||||
# from https://github.com/github/gitignore/blob/master/Node.gitignore
|
||||
lib-cov
|
||||
*.seed
|
||||
*.log
|
||||
*.csv
|
||||
*.dat
|
||||
*.out
|
||||
*.pid
|
||||
*.gz
|
||||
*.swp
|
||||
tags
|
||||
pids
|
||||
logs
|
||||
results
|
||||
build
|
||||
|
||||
node_modules
|
||||
|
||||
# extras
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
.project
|
||||
peerdb.json
|
||||
|
||||
npm-debug.log
|
||||
.nodemonignore
|
||||
|
||||
yarn.lock
|
||||
*.log
|
||||
.DS_Store
|
||||
db/txs/*
|
||||
db/txs
|
||||
|
||||
65
.jscsrc
Executable file
@ -0,0 +1,65 @@
|
||||
{
|
||||
"excludeFiles": ["node_modules/**", "mynode/**"],
|
||||
|
||||
"requireCurlyBraces": [
|
||||
"if",
|
||||
"else",
|
||||
"for",
|
||||
"while",
|
||||
"do",
|
||||
"try",
|
||||
"catch"
|
||||
],
|
||||
"requireOperatorBeforeLineBreak": true,
|
||||
"requireCamelCaseOrUpperCaseIdentifiers": true,
|
||||
"maximumLineLength": {
|
||||
"value": 200,
|
||||
"allowComments": true,
|
||||
"allowRegex": true
|
||||
},
|
||||
"validateIndentation": 2,
|
||||
"validateQuoteMarks": "'",
|
||||
|
||||
"disallowMultipleLineStrings": true,
|
||||
"disallowMixedSpacesAndTabs": true,
|
||||
"disallowTrailingWhitespace": true,
|
||||
"disallowSpaceAfterPrefixUnaryOperators": true,
|
||||
"disallowMultipleVarDecl": null,
|
||||
|
||||
"requireSpaceAfterKeywords": [
|
||||
"if",
|
||||
"else",
|
||||
"for",
|
||||
"while",
|
||||
"do",
|
||||
"switch",
|
||||
"return",
|
||||
"try",
|
||||
"catch"
|
||||
],
|
||||
"requireSpaceBeforeBinaryOperators": [
|
||||
"=", "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", ">>>=",
|
||||
"&=", "|=", "^=", "+=",
|
||||
|
||||
"+", "-", "*", "/", "%", "<<", ">>", ">>>", "&",
|
||||
"|", "^", "&&", "||", "===", "==", ">=",
|
||||
"<=", "<", ">", "!=", "!=="
|
||||
],
|
||||
"requireSpaceAfterBinaryOperators": true,
|
||||
"requireSpacesInConditionalExpression": true,
|
||||
"requireSpaceBeforeBlockStatements": true,
|
||||
"disallowSpacesInsideObjectBrackets": "all",
|
||||
"disallowSpacesInsideArrayBrackets": "all",
|
||||
"disallowSpacesInsideParentheses": true,
|
||||
|
||||
"disallowMultipleLineBreaks": true,
|
||||
|
||||
"disallowCommaBeforeLineBreak": null,
|
||||
"disallowDanglingUnderscores": null,
|
||||
"disallowEmptyBlocks": null,
|
||||
"disallowTrailingComma": null,
|
||||
"requireCommaBeforeLineBreak": null,
|
||||
"requireDotNotation": null,
|
||||
"requireMultipleVarDecl": null,
|
||||
"requireParenthesesAroundIIFE": true
|
||||
}
|
||||
@ -1,5 +1,8 @@
|
||||
sudo: false
|
||||
language: node_js
|
||||
node_js:
|
||||
- 'v8'
|
||||
install:
|
||||
- npm install
|
||||
after_success:
|
||||
- yarn send-coverage
|
||||
|
||||
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2013-2017 BitPay, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
62
app/.angular-cli.json
Normal file
@ -0,0 +1,62 @@
|
||||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"project": {
|
||||
"name": "insight-ui"
|
||||
},
|
||||
"apps": [
|
||||
{
|
||||
"root": "src",
|
||||
"outDir": "dist",
|
||||
"assets": [
|
||||
"assets",
|
||||
"favicon.ico"
|
||||
],
|
||||
"index": "index.html",
|
||||
"main": "app/main.ts",
|
||||
"polyfills": "polyfills.ts",
|
||||
"test": "test.ts",
|
||||
"tsconfig": "tsconfig.app.json",
|
||||
"testTsconfig": "tsconfig.spec.json",
|
||||
"prefix": "app",
|
||||
"scripts": [],
|
||||
"environmentSource": "environments/environment.ts",
|
||||
"environments": {
|
||||
"dev": "environments/environment.ts",
|
||||
"prod": "environments/environment.prod.ts"
|
||||
}
|
||||
}
|
||||
],
|
||||
"e2e": {
|
||||
"protractor": {
|
||||
"config": "./protractor.conf.js"
|
||||
}
|
||||
},
|
||||
"lint": [
|
||||
{
|
||||
"project": "src/tsconfig.app.json"
|
||||
},
|
||||
{
|
||||
"project": "src/tsconfig.spec.json"
|
||||
},
|
||||
{
|
||||
"project": "e2e/tsconfig.e2e.json"
|
||||
}
|
||||
],
|
||||
"test": {
|
||||
"karma": {
|
||||
"config": "./karma.conf.js"
|
||||
},
|
||||
"codeCoverage": {
|
||||
"exclude": [
|
||||
"src/polyfills.ts",
|
||||
"src/test.ts",
|
||||
"src/mocks.ts",
|
||||
"**/*.mock.ts"
|
||||
]
|
||||
}
|
||||
},
|
||||
"defaults": {
|
||||
"styleExt": "css",
|
||||
"component": {}
|
||||
}
|
||||
}
|
||||
40
app/.gitignore
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
# Specifies intentionally untracked files to ignore when using Git
|
||||
# http://git-scm.com/docs/gitignore
|
||||
|
||||
*~
|
||||
*.sw[mnpcod]
|
||||
*.log
|
||||
*.tmp
|
||||
*.tmp.*
|
||||
log.txt
|
||||
*.sublime-project
|
||||
*.sublime-workspace
|
||||
.vscode/
|
||||
npm-debug.log*
|
||||
|
||||
.sourcemaps/
|
||||
|
||||
.idea/
|
||||
.sass-cache/
|
||||
.tmp/
|
||||
.versions/
|
||||
coverage/
|
||||
dist/
|
||||
node_modules/
|
||||
tmp/
|
||||
temp/
|
||||
hooks/
|
||||
platforms/
|
||||
plugins/
|
||||
plugins/android.json
|
||||
plugins/ios.json
|
||||
www/
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# e2e
|
||||
/e2e/*.js
|
||||
/e2e/*.map
|
||||
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
UserInterfaceState.xcuserstate
|
||||
24
app/README.md
Normal file
@ -0,0 +1,24 @@
|
||||
[](https://travis-ci.org/bitpay/insight-ui)
|
||||
[](https://codecov.io/github/bitpay/insight-ui?branch=ionic)
|
||||
|
||||
# Insight UI
|
||||
|
||||
## Install & Start
|
||||
You need to be running [the latest node LTS](https://nodejs.org/en/download/) or newer.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/bitpay/insight-ui.git
|
||||
cd insight-ui/app
|
||||
npm install
|
||||
npm start
|
||||
```
|
||||
|
||||
## Run Unit Tests
|
||||
```bash
|
||||
npm test
|
||||
```
|
||||
|
||||
## Run E2E
|
||||
```
|
||||
npm run e2e
|
||||
```
|
||||
32
app/e2e/app.e2e-spec.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import { browser, element, by } from 'protractor';
|
||||
|
||||
describe('InsightApp', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
browser.get('');
|
||||
});
|
||||
|
||||
it('should have a title', () => {
|
||||
expect(browser.getTitle()).toEqual('Insight');
|
||||
});
|
||||
|
||||
it('should have {nav}', () => {
|
||||
expect(element(by.css('ion-navbar')).isPresent()).toEqual(true);
|
||||
});
|
||||
|
||||
it('has a menu button that displays the left menu', () => {
|
||||
element(by.css('.bar-button-menutoggle')).click()
|
||||
.then(() => {
|
||||
browser.driver.sleep(2000); // wait for the animation
|
||||
expect(element(by.css('ion-menu')).isPresent()).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('the left menu has a link with title Home', () => {
|
||||
element(by.css('.bar-button-menutoggle')).click()
|
||||
.then(() => {
|
||||
browser.driver.sleep(2000); // wait for the animation
|
||||
expect(element.all(by.css('ion-label')).first().getText()).toEqual('Home');
|
||||
});
|
||||
});
|
||||
});
|
||||
22
app/e2e/broadcastTxPage.e2e-spec.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { browser, element, by, ElementFinder } from 'protractor';
|
||||
|
||||
describe('BroadcastTxPage', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
browser.get('');
|
||||
});
|
||||
|
||||
it('should have an input field', () => {
|
||||
element(by.css('.bar-button-menutoggle')).click().then(() => {
|
||||
browser.driver.sleep(2000); // wait for the animation
|
||||
element.all(by.className('input-wrapper')).then((items) => {
|
||||
items[2].click();
|
||||
browser.driver.sleep(2000); // wait for the animation
|
||||
let theElem = element.all(by.css('ion-label')).first;
|
||||
console.log(theElem);
|
||||
expect(element.all(by.css('ion-input')).first().isPresent()).toEqual(true);
|
||||
return items[1];
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
12
app/e2e/tsconfig.e2e.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"extends": "../tsconfig.ng-cli.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/e2e",
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"node"
|
||||
]
|
||||
}
|
||||
}
|
||||
14
app/ionic.config.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "insight",
|
||||
"app_id": "",
|
||||
"type": "ionic-angular",
|
||||
"integrations": {
|
||||
"cordova": {}
|
||||
},
|
||||
"proxies": [
|
||||
{
|
||||
"path": "/api",
|
||||
"proxyUrl": "https://bch-insight.bitpay.com/api"
|
||||
}
|
||||
]
|
||||
}
|
||||
44
app/karma.conf.js
Normal file
@ -0,0 +1,44 @@
|
||||
// Karma configuration file, see link for more information
|
||||
// https://karma-runner.github.io/0.13/config/configuration-file.html
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular/cli'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage-istanbul-reporter'),
|
||||
require('@angular/cli/plugins/karma')
|
||||
],
|
||||
client:{
|
||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
files: [
|
||||
{ pattern: './src/test.ts', watched: false }
|
||||
],
|
||||
preprocessors: {
|
||||
'./src/test.ts': ['@angular/cli']
|
||||
},
|
||||
mime: {
|
||||
'text/x-typescript': ['ts','tsx']
|
||||
},
|
||||
coverageIstanbulReporter: {
|
||||
reports: [ 'html', 'lcovonly' ],
|
||||
fixWebpackSourcePaths: true
|
||||
},
|
||||
angularCli: {
|
||||
environment: 'dev'
|
||||
},
|
||||
reporters: config.angularCli && config.angularCli.codeCoverage
|
||||
? ['progress', 'coverage-istanbul']
|
||||
: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
singleRun: false
|
||||
});
|
||||
};
|
||||
14361
app/package-lock.json
generated
Normal file
70
app/package.json
Normal file
@ -0,0 +1,70 @@
|
||||
{
|
||||
"name": "insight-app",
|
||||
"private": true,
|
||||
"insightConfig": {
|
||||
"apiPrefix": "api",
|
||||
"routePrefix": ""
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "ionic-app-scripts clean",
|
||||
"build": "ionic-app-scripts build",
|
||||
"ionic:build": "ionic-app-scripts build",
|
||||
"ionic:serve": "ionic-app-scripts serve",
|
||||
"e2e": "ionic-app-scripts build && protractor",
|
||||
"postinstall": "webdriver-manager update --gecko false",
|
||||
"start": "ionic serve",
|
||||
"test": "ng test --code-coverage",
|
||||
"test:unit-e2e": "ng test --watch=false --code-coverage --browsers ChromeHeadless && npm run e2e --browsers ChromeHeadless",
|
||||
"test:ci": "ng test --watch=false --code-coverage --browsers ChromeHeadless",
|
||||
"cov": "opn coverage/index.html"
|
||||
},
|
||||
"dependencies": {
|
||||
"@angular/common": "4.1.3",
|
||||
"@angular/compiler": "4.1.3",
|
||||
"@angular/compiler-cli": "4.1.3",
|
||||
"@angular/core": "4.1.3",
|
||||
"@angular/forms": "4.1.3",
|
||||
"@angular/http": "4.1.3",
|
||||
"@angular/platform-browser": "4.1.3",
|
||||
"@angular/platform-browser-dynamic": "4.1.3",
|
||||
"@angular/router": "4.1.3",
|
||||
"@ionic-native/core": "3.10.2",
|
||||
"@ionic-native/splash-screen": "3.10.2",
|
||||
"@ionic-native/status-bar": "3.10.2",
|
||||
"@ionic/storage": "2.0.1",
|
||||
"angular2-moment": "^1.6.0",
|
||||
"angular2-qrcode": "^2.0.1",
|
||||
"ionic-angular": "3.4.2",
|
||||
"ionicons": "3.0.0",
|
||||
"rxjs": "5.4.0",
|
||||
"sw-toolbox": "3.6.0",
|
||||
"zone.js": "0.8.12"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/cli": "^1.1.2",
|
||||
"@ionic/app-scripts": "1.3.7",
|
||||
"@types/jasmine": "2.5.41",
|
||||
"@types/node": "7.0.4",
|
||||
"codecov": "2.2.0",
|
||||
"ionic": "3.20.0",
|
||||
"jasmine-core": "2.5.2",
|
||||
"jasmine-spec-reporter": "3.2.0",
|
||||
"karma": "1.4.1",
|
||||
"karma-chrome-launcher": "2.1.1",
|
||||
"karma-cli": "1.0.1",
|
||||
"karma-coverage-istanbul-reporter": "1.2.1",
|
||||
"karma-jasmine": "1.1.0",
|
||||
"karma-jasmine-html-reporter": "0.2.2",
|
||||
"opn-cli": "^3.1.0",
|
||||
"protractor": "5.1.2",
|
||||
"serve-static": "1.12.3",
|
||||
"ts-node": "3.0.4",
|
||||
"tslint": "5.3.2",
|
||||
"tslint-eslint-rules": "4.1.1",
|
||||
"typescript": "2.3.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"license": "MIT"
|
||||
}
|
||||
33
app/protractor.conf.js
Normal file
@ -0,0 +1,33 @@
|
||||
// Protractor configuration file, see link for more information
|
||||
// https://github.com/angular/protractor/blob/master/lib/config.ts
|
||||
|
||||
const { SpecReporter } = require('jasmine-spec-reporter');
|
||||
|
||||
exports.config = {
|
||||
allScriptsTimeout: 11000,
|
||||
specs: [
|
||||
'./e2e/**/*.e2e-spec.ts'
|
||||
],
|
||||
capabilities: {
|
||||
'browserName': 'chrome'
|
||||
},
|
||||
directConnect: true,
|
||||
baseUrl: 'http://localhost:4200/',
|
||||
framework: 'jasmine',
|
||||
jasmineNodeOpts: {
|
||||
showColors: true,
|
||||
defaultTimeoutInterval: 30000,
|
||||
print: function() {}
|
||||
},
|
||||
useAllAngular2AppRoots: true,
|
||||
beforeLaunch: function() {
|
||||
require('ts-node').register({
|
||||
project: 'e2e/tsconfig.e2e.json'
|
||||
});
|
||||
|
||||
require('connect')().use(require('serve-static')('www')).listen(4200);
|
||||
},
|
||||
onPrepare() {
|
||||
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
|
||||
}
|
||||
};
|
||||
BIN
app/resources/android/icon/drawable-hdpi-icon.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
app/resources/android/icon/drawable-ldpi-icon.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
app/resources/android/icon/drawable-mdpi-icon.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
app/resources/android/icon/drawable-xhdpi-icon.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
app/resources/android/icon/drawable-xxhdpi-icon.png
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
app/resources/android/icon/drawable-xxxhdpi-icon.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
app/resources/android/splash/drawable-land-hdpi-screen.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
app/resources/android/splash/drawable-land-ldpi-screen.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
app/resources/android/splash/drawable-land-mdpi-screen.png
Normal file
|
After Width: | Height: | Size: 6.9 KiB |
BIN
app/resources/android/splash/drawable-land-xhdpi-screen.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
app/resources/android/splash/drawable-land-xxhdpi-screen.png
Normal file
|
After Width: | Height: | Size: 58 KiB |
BIN
app/resources/android/splash/drawable-land-xxxhdpi-screen.png
Normal file
|
After Width: | Height: | Size: 87 KiB |
BIN
app/resources/android/splash/drawable-port-hdpi-screen.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
app/resources/android/splash/drawable-port-ldpi-screen.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
app/resources/android/splash/drawable-port-mdpi-screen.png
Normal file
|
After Width: | Height: | Size: 7.0 KiB |
BIN
app/resources/android/splash/drawable-port-xhdpi-screen.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
app/resources/android/splash/drawable-port-xxhdpi-screen.png
Normal file
|
After Width: | Height: | Size: 54 KiB |
BIN
app/resources/android/splash/drawable-port-xxxhdpi-screen.png
Normal file
|
After Width: | Height: | Size: 80 KiB |
BIN
app/resources/icon.png
Normal file
|
After Width: | Height: | Size: 59 KiB |
BIN
app/resources/ios/icon/icon-40.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
app/resources/ios/icon/icon-40@2x.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
app/resources/ios/icon/icon-40@3x.png
Normal file
|
After Width: | Height: | Size: 5.9 KiB |
BIN
app/resources/ios/icon/icon-50.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
app/resources/ios/icon/icon-50@2x.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
app/resources/ios/icon/icon-60.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
app/resources/ios/icon/icon-60@2x.png
Normal file
|
After Width: | Height: | Size: 5.9 KiB |
BIN
app/resources/ios/icon/icon-60@3x.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
app/resources/ios/icon/icon-72.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
app/resources/ios/icon/icon-72@2x.png
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
app/resources/ios/icon/icon-76.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
app/resources/ios/icon/icon-76@2x.png
Normal file
|
After Width: | Height: | Size: 8.1 KiB |
BIN
app/resources/ios/icon/icon-83.5@2x.png
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
BIN
app/resources/ios/icon/icon-small.png
Normal file
|
After Width: | Height: | Size: 818 B |
BIN
app/resources/ios/icon/icon-small@2x.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
app/resources/ios/icon/icon-small@3x.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
app/resources/ios/icon/icon.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
app/resources/ios/icon/icon@2x.png
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
BIN
app/resources/ios/splash/Default-568h@2x~iphone.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
app/resources/ios/splash/Default-667h.png
Normal file
|
After Width: | Height: | Size: 40 KiB |
BIN
app/resources/ios/splash/Default-736h.png
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
app/resources/ios/splash/Default-Landscape-736h.png
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
app/resources/ios/splash/Default-Landscape@2x~ipad.png
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
app/resources/ios/splash/Default-Landscape~ipad.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
app/resources/ios/splash/Default-Portrait@2x~ipad.png
Normal file
|
After Width: | Height: | Size: 97 KiB |
BIN
app/resources/ios/splash/Default-Portrait~ipad.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
app/resources/ios/splash/Default@2x~iphone.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
app/resources/ios/splash/Default~iphone.png
Normal file
|
After Width: | Height: | Size: 7.0 KiB |
BIN
app/resources/splash.png
Normal file
|
After Width: | Height: | Size: 61 KiB |
62
app/src/app/app.component.ts
Normal file
@ -0,0 +1,62 @@
|
||||
import { Component, ViewChild } from '@angular/core';
|
||||
import { Platform, MenuController, Nav } from 'ionic-angular';
|
||||
import { StatusBar } from '@ionic-native/status-bar';
|
||||
import { SplashScreen } from '@ionic-native/splash-screen';
|
||||
import {
|
||||
HomePage
|
||||
} from '../pages';
|
||||
|
||||
@Component({
|
||||
templateUrl: './app.html'
|
||||
})
|
||||
export class InsightApp {
|
||||
@ViewChild(Nav) public nav: Nav;
|
||||
|
||||
private menu: MenuController;
|
||||
private platform: Platform;
|
||||
private splash: SplashScreen;
|
||||
private status: StatusBar;
|
||||
|
||||
public rootPage: any;
|
||||
public pages: Array<{ title: string; component: any }>;
|
||||
|
||||
constructor(
|
||||
platform: Platform,
|
||||
menu: MenuController,
|
||||
splash: SplashScreen,
|
||||
status: StatusBar
|
||||
) {
|
||||
this.menu = menu;
|
||||
this.platform = platform;
|
||||
this.splash = splash;
|
||||
this.status = status;
|
||||
|
||||
this.rootPage = HomePage;
|
||||
this.initializeApp();
|
||||
|
||||
// set our app's pages
|
||||
this.pages = [
|
||||
{ title: 'Home', component: HomePage },
|
||||
{ title: 'Blocks', component: 'blocks' },
|
||||
{ title: 'Broadcast Transaction', component: 'BroadcastTxPage' }
|
||||
// { title: 'Verify Signed Message', component: VerifyMessagePage },
|
||||
// { title: 'Node Status', component: NodeStatusPage }
|
||||
];
|
||||
}
|
||||
|
||||
private initializeApp(): void {
|
||||
this.platform.ready().then(() => {
|
||||
// Okay, so the platform is ready and our plugins are available.
|
||||
// Here you can do any higher level native things you might need.
|
||||
this.status.styleDefault();
|
||||
this.splash.hide();
|
||||
});
|
||||
}
|
||||
|
||||
public openPage(page: any): void {
|
||||
// close the menu when clicking a link from the menu
|
||||
this.menu.close();
|
||||
// navigate to the new page if it is not the current page
|
||||
this.nav.setRoot(page.component);
|
||||
}
|
||||
}
|
||||
13
app/src/app/app.html
Normal file
@ -0,0 +1,13 @@
|
||||
<ion-menu [content]="content">
|
||||
|
||||
<ion-content>
|
||||
<ion-list>
|
||||
<button ion-item *ngFor="let p of pages" (click)="openPage(p)">
|
||||
{{p.title}}
|
||||
</button>
|
||||
</ion-list>
|
||||
</ion-content>
|
||||
|
||||
</ion-menu>
|
||||
|
||||
<ion-nav [root]="rootPage" #content swipeBackEnabled="false"></ion-nav>
|
||||
44
app/src/app/app.module.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import { HttpModule } from '@angular/http';
|
||||
import { NgModule, ErrorHandler } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';
|
||||
import { StatusBar } from '@ionic-native/status-bar';
|
||||
import { SplashScreen } from '@ionic-native/splash-screen';
|
||||
import { InsightApp } from './app.component';
|
||||
import { PagesModule, HomePage, BlocksPage, NodeStatusPage, VerifyMessagePage } from '../pages';
|
||||
import { BlocksService, StorageService } from '../services';
|
||||
import { ApiProvider } from '../providers/api/api';
|
||||
import { CurrencyProvider } from '../providers/currency/currency';
|
||||
import { BlocksProvider } from '../providers/blocks/blocks';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
InsightApp
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
HttpModule,
|
||||
PagesModule,
|
||||
IonicModule.forRoot(InsightApp)
|
||||
],
|
||||
bootstrap: [IonicApp],
|
||||
entryComponents: [
|
||||
InsightApp,
|
||||
HomePage,
|
||||
BlocksPage,
|
||||
NodeStatusPage,
|
||||
VerifyMessagePage
|
||||
],
|
||||
providers: [
|
||||
StatusBar,
|
||||
SplashScreen,
|
||||
StorageService,
|
||||
BlocksService,
|
||||
{provide: ErrorHandler, useClass: IonicErrorHandler},
|
||||
ApiProvider,
|
||||
CurrencyProvider,
|
||||
BlocksProvider
|
||||
]
|
||||
})
|
||||
|
||||
export class AppModule {}
|
||||
84
app/src/app/app.scss
Normal file
@ -0,0 +1,84 @@
|
||||
// http://ionicframework.com/docs/v2/theming/
|
||||
|
||||
// App Global Sass
|
||||
// --------------------------------------------------
|
||||
// Put style rules here that you want to apply globally. These
|
||||
// styles are for the entire app and not just one component.
|
||||
// Additionally, this file can be also used as an entry point
|
||||
// to import other Sass files to be included in the output CSS.
|
||||
|
||||
body {
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
a {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.ellipsis {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.item-hash {
|
||||
@extend .ellipsis;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.list--summary {
|
||||
ion-label {
|
||||
color: #334;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
ion-item {
|
||||
color: #99a;
|
||||
font-size: 1.125rem;
|
||||
@media screen and (min-width: $desktop-min-width) {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
ion-note {
|
||||
color: #99a;
|
||||
max-width: 80%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.grid--table {
|
||||
margin: 10px 0 20px;
|
||||
|
||||
.col {
|
||||
padding: 1em 0.6em;
|
||||
}
|
||||
|
||||
ion-row {
|
||||
border-top: 1px solid #dde;
|
||||
|
||||
&:first-child {
|
||||
background-color: #fff;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
&:nth-child(even) {
|
||||
background-color: #f8f8f9;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Shared Sass variables, which can be used to adjust Ionic's
|
||||
// default Sass variables, belong in "theme/variables.scss".
|
||||
//
|
||||
// To declare rules for a specific mode, create a child rule
|
||||
// for the .md, .ios, or .wp mode classes. The mode class is
|
||||
// automatically applied to the <body> element in the app.
|
||||
44
app/src/app/app.spec.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import { InsightApp } from './app.component';
|
||||
import { TestBed, getTestBed } from '@angular/core/testing';
|
||||
import { Platform } from 'ionic-angular';
|
||||
import { NavMock } from '../mocks';
|
||||
import { PopoverController, MenuController } from 'ionic-angular';
|
||||
import { StatusBar } from '@ionic-native/status-bar';
|
||||
import { SplashScreen } from '@ionic-native/splash-screen';
|
||||
|
||||
describe('InsightApp', () => {
|
||||
let injector: TestBed;
|
||||
let app: InsightApp;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [
|
||||
PopoverController,
|
||||
InsightApp,
|
||||
Platform,
|
||||
MenuController,
|
||||
SplashScreen,
|
||||
StatusBar
|
||||
]
|
||||
});
|
||||
injector = getTestBed();
|
||||
app = injector.get(InsightApp);
|
||||
|
||||
app['nav'] = (<any>new NavMock());
|
||||
});
|
||||
|
||||
it('initializes with three possible pages', () => {
|
||||
expect(app['pages'].length).toEqual(3);
|
||||
});
|
||||
|
||||
it('initializes with a root page', () => {
|
||||
expect(app['rootPage']).not.toBe(null);
|
||||
});
|
||||
|
||||
it('opens a page', () => {
|
||||
spyOn(app['menu'], 'close');
|
||||
spyOn(app['nav'], 'setRoot');
|
||||
app.openPage(app['pages'][1]);
|
||||
expect(app['menu']['close']).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
5
app/src/app/main.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app.module';
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule);
|
||||
BIN
app/src/assets/icon/favicon.ico
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
app/src/assets/img/angularjs.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
29
app/src/assets/img/bitcore.svg
Normal file
|
After Width: | Height: | Size: 15 KiB |
14
app/src/assets/img/currency_logos/bch.svg
Normal file
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="49px" height="30px" viewBox="0 0 49 30" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 46.2 (44496) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>cash</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Symbols" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Invoice---Details---toggle-13" transform="translate(-15.000000, -66.000000)" fill-rule="nonzero" fill="#70C559">
|
||||
<g id="cash" transform="translate(15.000000, 66.000000)">
|
||||
<path d="M13.8417063,-9.23705556e-14 C10.3638666,2.45824779 7.71855988,6.11178429 6.60498615,10.5439372 C4.70445891,18.0998581 7.80802299,25.7315444 13.8323317,30 L0,30 L0,6.67235157e-12 L13.8417063,6.67174941e-12 L13.8417063,-9.23705556e-14 Z M35.4255188,2.16006456e-11 L49,2.16000551e-11 L49,30 L35.4177702,30 C38.8953546,27.5421934 41.5405004,23.8894637 42.6545185,19.458134 C44.5543534,11.900549 41.4505764,4.26854241 35.4255188,2.1236346e-11 L35.4255188,2.16006456e-11 Z M39.3004107,18.6286839 C37.2802686,26.6643836 29.0735016,31.5548028 20.9697739,29.5509168 C12.8693548,27.5474997 7.93811007,19.4082073 9.95919725,11.3729763 C11.9783938,3.33633912 20.185161,-1.55454875 28.2865254,0.448868418 C36.3897804,2.45228559 41.3205524,10.5925155 39.3004107,18.6286839 Z M25.404827,8.31840135 L24.822017,5.61021006 L23.1646362,5.95837059 L23.7321322,8.59517337 C23.2964321,8.68671195 22.8528909,8.78878287 22.412286,8.89047021 L21.8413778,6.23613729 L20.1848384,6.58389075 L20.7668159,9.29144802 C20.4095444,9.37407702 20.0585751,9.45469416 19.7150084,9.52706466 L17.4268281,9.99789864 L17.8061139,11.7584155 C17.8061139,11.7584155 19.0250623,11.4782322 19.0095416,11.5049211 C19.6809284,11.3641687 19.9828396,11.7059324 20.1183742,12.0270932 L21.7146405,19.4461225 C21.7303963,19.6624491 21.6782983,20.0235742 21.2094313,20.1228629 C21.2346595,20.1370971 20.0045444,20.375508 20.0045444,20.375508 L20.0988542,22.4133317 L22.2557355,21.9603946 C22.6572213,21.8765944 23.053614,21.8004421 23.44186,21.7214914 L24.0319506,24.4603751 L25.6876485,24.1130287 L25.1044355,21.4029588 C25.5610391,21.31686 26.0017437,21.2280845 26.4311504,21.1375167 L27.0109069,23.835262 L28.6682877,23.4871014 L28.0804623,20.7528244 C30.8327059,20.0087698 32.6327287,18.9010983 32.3148875,16.247723 C32.0594765,14.1110581 30.8671217,13.3840872 29.2040862,13.3384078 C30.0603063,12.6499773 30.4765778,11.6663412 30.0286414,10.2671807 C29.4197843,8.35437249 27.5843909,8.05563042 25.404827,8.31840135 Z M28.8925748,16.4400896 C29.3339492,18.4867945 25.7599728,18.9938427 24.6369247,19.2307446 L23.8564384,15.6015987 C24.9801043,15.3659532 28.4333066,14.3051001 28.8925748,16.4400896 Z M23.3654016,14.0925774 L22.6572494,10.8011688 C23.5928708,10.6046501 26.4682721,9.69163557 26.886443,11.6339622 C27.2866494,13.4963329 24.3010229,13.8960587 23.3654016,14.0925774 Z" id="Cash"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.0 KiB |
15
app/src/assets/img/currency_logos/btc.svg
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="30px" height="30px" viewBox="0 0 30 30" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 46.2 (44496) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>bitcoin</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Symbols" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Invoice---Details---toggle-12" transform="translate(-14.000000, -65.000000)" fill-rule="nonzero">
|
||||
<g id="bitcoin" transform="translate(14.000000, 65.000000)">
|
||||
<path d="M29.488125,18.7144615 C27.4907812,26.6007692 19.3776562,31.4141538 11.3475,29.448 C3.3384375,27.4813846 -1.550625,19.4930769 0.44671875,11.6067692 C2.44359375,3.72092308 10.5571875,-1.09246154 18.56625,0.873692308 C26.5964062,2.81953846 31.485,10.8286154 29.488125,18.7144615" id="Shape" fill="#F8AE2A"></path>
|
||||
<path d="M18.8160938,13.2456923 C18.3792187,15.0687692 15.508125,14.1876923 14.5720313,13.9624615 L15.3628125,10.7261538 C16.2778125,10.9513846 19.2735937,11.3409231 18.8160937,13.2456923 L18.8160938,13.2456923 Z M18.358125,18.4689231 C17.88,20.4761538 14.42625,19.4316923 13.32375,19.1653846 L14.176875,15.6013846 C15.3,15.8676923 18.8573438,16.3592308 18.358125,18.4689231 Z M22.06125,13.2456923 C22.3317187,11.2790769 20.8129687,10.2549231 18.7326562,9.55846154 L19.3776562,6.89584615 L17.7342188,6.50676923 L17.1103125,9.108 C16.6734375,9.00553846 16.2365625,8.90307692 15.7996875,8.82138462 L16.4235937,6.21969231 L14.7595313,5.83061538 L14.1145313,8.49369231 C13.760625,8.41153846 13.4071875,8.35015385 13.0532813,8.268 L10.7859375,7.73584615 L10.3696875,9.45646154 C10.3696875,9.45646154 11.5973438,9.72230769 11.555625,9.74307692 C12.22125,9.90692308 12.3459375,10.3370769 12.3253125,10.6647692 L11.5973438,13.6961538 C11.6385938,13.7169231 11.7014063,13.7169231 11.76375,13.7575385 C11.7014063,13.7372308 11.6596875,13.7372308 11.5973438,13.7169231 L10.5984375,17.9566154 C10.5154688,18.1615385 10.3073438,18.4481538 9.84984375,18.3461538 C9.87046875,18.3664615 8.64328125,18.0590769 8.64328125,18.0590769 L7.8525,19.9232308 L9.99515625,20.4147692 C10.3907812,20.5172308 10.7859375,20.5989231 11.1604687,20.7013846 L10.5154688,23.3847692 L12.1589062,23.7738462 L12.8039062,21.1112308 C13.2614063,21.234 13.6982813,21.3364615 14.1145312,21.4389231 L13.4695312,24.0812308 L15.1129687,24.4703077 L15.7579687,21.7873846 C18.56625,22.2789231 20.6671875,22.0532308 21.5203125,19.5341538 C22.2070312,17.5264615 21.4579687,16.3795385 19.9603125,15.6216923 C21.0628125,15.3756923 21.853125,14.6796923 22.06125,13.2456923 L22.06125,13.2456923 Z" id="Shape" fill="#FFFFFF"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.7 KiB |
16
app/src/assets/img/currency_logos/ltc.svg
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="30px" height="30px" viewBox="0 0 30 30" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 46.2 (44496) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>litecoin</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Exploration" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="select-currency" transform="translate(-135.000000, -516.000000)" fill-rule="nonzero" fill="#BEBEBE">
|
||||
<g id="LTC" transform="translate(135.000000, 514.000000)">
|
||||
<g id="litecoin" transform="translate(0.000000, 2.000000)">
|
||||
<path d="M14.9978166,0.0793957695 C6.7571516,0.0793957695 0.076944392,6.75969362 0.076944392,15.0002674 C0.076944392,23.240932 6.7571516,29.9213166 14.9978166,29.9213166 C23.2383906,29.9213166 29.9186882,23.240932 29.9186882,15.0002674 C29.9186882,6.75969362 23.2383,0.0793957695 14.9978166,0.0793957695 Z M12.6942498,6.99841486 L17.3093483,6.99841486 L15.6819997,13.1259761 L17.9406036,12.3008837 L17.9600755,12.35399 L17.3893613,14.4987689 L15.0948236,15.3369607 L14.1258136,18.986236 L21.793452,18.986236 L21.0060653,21.9194637 L8.72315148,21.9194637 L9.97751782,17.2066495 L8.20200344,17.8552523 L8.78918003,15.6440909 L10.5659338,14.9949571 L12.6942498,6.99841486 Z" id="Fill-1"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
BIN
app/src/assets/img/leveldb.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
app/src/assets/img/nodejs.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
19
app/src/components/components.module.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { IonicModule } from 'ionic-angular';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
],
|
||||
imports: [
|
||||
FormsModule,
|
||||
IonicModule,
|
||||
ReactiveFormsModule
|
||||
],
|
||||
exports: [
|
||||
],
|
||||
entryComponents: [],
|
||||
providers: []
|
||||
})
|
||||
|
||||
export class ComponentsModule {}
|
||||
21
app/src/components/denomination/denomination.html
Normal file
@ -0,0 +1,21 @@
|
||||
<ion-list radio-group [(ngModel)]="currencyProvider.currencySymbol" (ionChange)="currencyProvider.setCurrency(currencyProvider.currencySymbol)">
|
||||
<ion-list-header *ngIf="switcherOn">
|
||||
Blockchain
|
||||
</ion-list-header>
|
||||
|
||||
<ion-row *ngIf="switcherOn">
|
||||
<ion-col *ngFor="let explorer of currencyProvider.explorers">
|
||||
<button (click)="changeExplorer(explorer)" ion-item detail-none class="text-button" text-center>
|
||||
<img src="assets/img/currency_logos/{{ explorer.ticker.toLowerCase() }}.svg" class="logo"/></button>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
|
||||
<ion-list-header>
|
||||
Units
|
||||
</ion-list-header>
|
||||
|
||||
<ion-item *ngFor="let unit of units">
|
||||
<ion-label color="dark">{{ unit }}</ion-label>
|
||||
<ion-radio value="{{ unit }}" (click)="close()"></ion-radio>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
19
app/src/components/denomination/denomination.module.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { IonicModule } from 'ionic-angular';
|
||||
import { DenominationComponent } from './denomination';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
DenominationComponent
|
||||
],
|
||||
imports: [
|
||||
IonicModule
|
||||
],
|
||||
exports: [
|
||||
DenominationComponent
|
||||
],
|
||||
entryComponents: [
|
||||
DenominationComponent
|
||||
]
|
||||
})
|
||||
export class DenominationComponentModule {}
|
||||
3
app/src/components/denomination/denomination.scss
Normal file
@ -0,0 +1,3 @@
|
||||
denomination {
|
||||
|
||||
}
|
||||
41
app/src/components/denomination/denomination.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { CurrencyProvider } from '../../providers/currency/currency';
|
||||
import { ViewController } from 'ionic-angular';
|
||||
import { Http } from '@angular/http';
|
||||
import { ApiProvider } from '../../providers/api/api';
|
||||
|
||||
@Component({
|
||||
selector: 'denomination',
|
||||
templateUrl: 'denomination.html'
|
||||
})
|
||||
export class DenominationComponent {
|
||||
|
||||
public switcherOn: boolean;
|
||||
public units: any = [];
|
||||
|
||||
constructor(
|
||||
public currencyProvider: CurrencyProvider,
|
||||
public viewCtrl: ViewController,
|
||||
public http: Http,
|
||||
public api: ApiProvider
|
||||
) {
|
||||
this.units = [
|
||||
'USD',
|
||||
this.currencyProvider.defaultCurrency,
|
||||
'm' + this.currencyProvider.defaultCurrency,
|
||||
'bits'
|
||||
];
|
||||
|
||||
this.switcherOn = currencyProvider.explorers.length > 1;
|
||||
}
|
||||
|
||||
public close(): void {
|
||||
this.viewCtrl.dismiss();
|
||||
}
|
||||
|
||||
public changeExplorer(explorer: any): void {
|
||||
this.close();
|
||||
let theUrl: string = explorer.url;
|
||||
window.location.href = theUrl;
|
||||
}
|
||||
}
|
||||
19
app/src/components/head-nav/head-nav.html
Normal file
@ -0,0 +1,19 @@
|
||||
<ion-navbar color="brand">
|
||||
<button ion-button menuToggle>
|
||||
<ion-icon name="menu"></ion-icon>
|
||||
</button>
|
||||
<ion-title>{{title}}</ion-title>
|
||||
<ion-buttons end>
|
||||
<button ion-button (click)="changeCurrency($event)">
|
||||
<ion-icon name="logo-bitcoin" *ngIf="currency.currencySymbol !== 'USD'"></ion-icon>
|
||||
<ion-icon name="logo-usd" *ngIf="currency.currencySymbol === 'USD'"></ion-icon> {{ currency.currencySymbol }}
|
||||
</button>
|
||||
<button ion-button icon-only (click)="toggleSearch()">
|
||||
<ion-icon name="search"></ion-icon>
|
||||
</button>
|
||||
</ion-buttons>
|
||||
</ion-navbar>
|
||||
|
||||
<form (ngSubmit)="search($event)">
|
||||
<ion-searchbar [hidden]="!showSearch" placeholder="{{ 'Search for block, transaction or address' }}" [(ngModel)]="q" name="search"></ion-searchbar>
|
||||
</form>
|
||||
18
app/src/components/head-nav/head-nav.module.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { IonicModule } from 'ionic-angular';
|
||||
import { HeadNavComponent } from './head-nav';
|
||||
import { DenominationComponentModule } from '../denomination/denomination.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
HeadNavComponent
|
||||
],
|
||||
imports: [
|
||||
IonicModule,
|
||||
DenominationComponentModule
|
||||
],
|
||||
exports: [
|
||||
HeadNavComponent
|
||||
]
|
||||
})
|
||||
export class HeadNavComponentModule {}
|
||||
3
app/src/components/head-nav/head-nav.scss
Normal file
@ -0,0 +1,3 @@
|
||||
head-nav {
|
||||
|
||||
}
|
||||
125
app/src/components/head-nav/head-nav.ts
Normal file
@ -0,0 +1,125 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Input } from '@angular/core';
|
||||
import { NavController } from 'ionic-angular';
|
||||
import { Http } from '@angular/http';
|
||||
import { ApiProvider } from '../../providers/api/api';
|
||||
import { CurrencyProvider } from '../../providers/currency/currency';
|
||||
import { ActionSheetController } from 'ionic-angular';
|
||||
import { PopoverController } from 'ionic-angular';
|
||||
import { ToastController } from 'ionic-angular';
|
||||
import { DenominationComponent } from '../denomination/denomination';
|
||||
|
||||
/**
|
||||
* Generated class for the HeadNavComponent component.
|
||||
*
|
||||
* See https://angular.io/docs/ts/latest/api/core/index/ComponentMetadata-class.html
|
||||
* for more info on Angular Components.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'head-nav',
|
||||
templateUrl: 'head-nav.html'
|
||||
})
|
||||
export class HeadNavComponent {
|
||||
|
||||
public showSearch: boolean = false;
|
||||
public loading: boolean;
|
||||
@Input() public title: string;
|
||||
public q: string;
|
||||
|
||||
constructor(
|
||||
private navCtrl: NavController,
|
||||
private http: Http,
|
||||
private api: ApiProvider,
|
||||
public currency: CurrencyProvider,
|
||||
public actionSheetCtrl: ActionSheetController,
|
||||
public popoverCtrl: PopoverController,
|
||||
public toastCtrl: ToastController
|
||||
) {
|
||||
}
|
||||
|
||||
public search(): void {
|
||||
this.showSearch = false;
|
||||
let apiPrefix: string = this.api.apiPrefix;
|
||||
|
||||
this.http.get(apiPrefix + 'block/' + this.q).subscribe(
|
||||
function (data: any): void {
|
||||
this.resetSearch();
|
||||
console.log('block', data);
|
||||
let parsedData: any = JSON.parse(data._body);
|
||||
this.navCtrl.push('block-detail', {
|
||||
'blockHash': parsedData.hash
|
||||
});
|
||||
}.bind(this),
|
||||
() => {
|
||||
this.http.get(apiPrefix + 'tx/' + this.q).subscribe(
|
||||
function (data: any): void {
|
||||
this.resetSearch();
|
||||
console.log('tx', data);
|
||||
let parsedData: any = JSON.parse(data._body);
|
||||
this.navCtrl.push('transaction', {
|
||||
'txId': parsedData.txid
|
||||
});
|
||||
}.bind(this),
|
||||
() => {
|
||||
this.http.get(apiPrefix + 'addr/' + this.q).subscribe(
|
||||
function (data: any): void {
|
||||
this.resetSearch();
|
||||
console.log('addr', data);
|
||||
let parsedData: any = JSON.parse(data._body);
|
||||
this.navCtrl.push('address', {
|
||||
'addrStr': parsedData.addrStr
|
||||
});
|
||||
}.bind(this),
|
||||
() => {
|
||||
this.http.get(apiPrefix + 'block-index/' + this.q).subscribe(
|
||||
function (data: any): void {
|
||||
this.resetSearch();
|
||||
let parsedData: any = JSON.parse(data._body);
|
||||
this.navCtrl.push('block-detail', {
|
||||
'blockHash': parsedData.blockHash
|
||||
});
|
||||
}.bind(this),
|
||||
function (): void {
|
||||
this.loading = false;
|
||||
this.reportBadQuery();
|
||||
}.bind(this)
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/* tslint:disable:no-unused-variable */
|
||||
private reportBadQuery(): void {
|
||||
this.presentToast();
|
||||
}
|
||||
|
||||
private presentToast(): void {
|
||||
const toast: any = this.toastCtrl.create({
|
||||
message: 'No matching records found!',
|
||||
duration: 3000,
|
||||
position: 'top'
|
||||
});
|
||||
toast.present();
|
||||
}
|
||||
|
||||
private resetSearch(): void {
|
||||
this.q = '';
|
||||
this.loading = false;
|
||||
}
|
||||
/* tslint:enable:no-unused-variable */
|
||||
|
||||
public changeCurrency(myEvent: any): void {
|
||||
let popover: any = this.popoverCtrl.create(DenominationComponent);
|
||||
popover.present({
|
||||
ev: myEvent
|
||||
});
|
||||
}
|
||||
|
||||
public toggleSearch(): void {
|
||||
this.showSearch = !this.showSearch;
|
||||
}
|
||||
}
|
||||
1
app/src/components/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './components.module';
|
||||
47
app/src/components/latest-blocks/latest-blocks.html
Normal file
@ -0,0 +1,47 @@
|
||||
<!-- Generated template for the LatestBlocksComponent component -->
|
||||
<div>
|
||||
<div *ngIf="loading">
|
||||
<ion-spinner name="crescent"></ion-spinner>
|
||||
</div>
|
||||
|
||||
<div *ngIf="!loading">
|
||||
<ion-grid class="grid--table">
|
||||
|
||||
<ion-row>
|
||||
<ion-col><b>Height</b></ion-col>
|
||||
<ion-col *ngIf="showTimeAs === 'age'"><b>Age</b></ion-col>
|
||||
<ion-col *ngIf="showTimeAs === 'timestamp'"><b>Timestamp</b></ion-col>
|
||||
<ion-col text-right><b>Transactions</b></ion-col>
|
||||
<ion-col hideWhen="portrait"><b>Mined By</b></ion-col>
|
||||
<ion-col text-right><b>Size</b></ion-col>
|
||||
</ion-row>
|
||||
|
||||
<ion-row *ngFor="let block of getBlocks()">
|
||||
<ion-col>
|
||||
<a (click)="goToBlock(block.hash)">{{block.height}}</a>
|
||||
</ion-col>
|
||||
<ion-col *ngIf="showTimeAs === 'age'">
|
||||
{{ block.time | amFromUnix | amTimeAgo }}
|
||||
</ion-col>
|
||||
<ion-col *ngIf="showTimeAs === 'timestamp'">
|
||||
{{ block.time * 1000 | date:'medium' }}
|
||||
</ion-col>
|
||||
<ion-col text-right>
|
||||
{{block.txlength}}
|
||||
</ion-col>
|
||||
<ion-col hideWhen="portrait">
|
||||
<a *ngIf="block.poolInfo.poolName" href="{{block.poolInfo.url}}">{{block.poolInfo.poolName}}</a>
|
||||
</ion-col>
|
||||
<ion-col text-right>
|
||||
{{ block.size }}
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
|
||||
<ion-row *ngIf="showAllBlocksButton">
|
||||
<ion-col text-center>
|
||||
<button ion-button (click)="goToBlocks()">See all blocks</button>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
</div>
|
||||
</div>
|
||||
18
app/src/components/latest-blocks/latest-blocks.module.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { IonicModule } from 'ionic-angular';
|
||||
import { LatestBlocksComponent } from './latest-blocks';
|
||||
import { MomentModule } from 'angular2-moment';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
LatestBlocksComponent
|
||||
],
|
||||
imports: [
|
||||
IonicModule,
|
||||
MomentModule
|
||||
],
|
||||
exports: [
|
||||
LatestBlocksComponent
|
||||
]
|
||||
})
|
||||
export class LatestBlocksComponentModule {}
|
||||
2
app/src/components/latest-blocks/latest-blocks.scss
Normal file
@ -0,0 +1,2 @@
|
||||
latest-blocks {
|
||||
}
|
||||
71
app/src/components/latest-blocks/latest-blocks.ts
Normal file
@ -0,0 +1,71 @@
|
||||
import { Component, NgZone, Input } from '@angular/core';
|
||||
import { BlocksProvider } from '../../providers/blocks/blocks';
|
||||
import { NavController } from 'ionic-angular';
|
||||
|
||||
/**
|
||||
* Generated class for the LatestBlocksComponent component.
|
||||
*
|
||||
* See https://angular.io/docs/ts/latest/api/core/index/ComponentMetadata-class.html
|
||||
* for more info on Angular Components.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'latest-blocks',
|
||||
templateUrl: 'latest-blocks.html'
|
||||
})
|
||||
export class LatestBlocksComponent {
|
||||
|
||||
public loading: boolean = true;
|
||||
public blocks: Array<any> = [];
|
||||
@Input() public numBlocks: number;
|
||||
@Input() public showAllBlocksButton: boolean;
|
||||
@Input() public showTimeAs: string;
|
||||
private reloadInterval: any;
|
||||
|
||||
constructor(private blocksProvider: BlocksProvider, private navCtrl: NavController, ngZone: NgZone) {
|
||||
this.loadBlocks();
|
||||
const seconds: number = 15;
|
||||
ngZone.runOutsideAngular(() => {
|
||||
this.reloadInterval = setInterval(
|
||||
function (): void {
|
||||
ngZone.run(function (): void {
|
||||
this.loadBlocks.call(this);
|
||||
}.bind(this));
|
||||
}.bind(this),
|
||||
1000 * seconds
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private loadBlocks(): void {
|
||||
this.blocksProvider.getBlocks().subscribe(
|
||||
(data) => {
|
||||
this.blocks = JSON.parse(data['_body']).blocks;
|
||||
this.loading = false;
|
||||
},
|
||||
(err) => {
|
||||
console.log('err', err);
|
||||
this.loading = false;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public goToBlock(blockHash: string): void {
|
||||
this.navCtrl.push('block-detail', {
|
||||
'blockHash': blockHash
|
||||
});
|
||||
}
|
||||
|
||||
public getBlocks(): Array<any> {
|
||||
/* tslint:disable:no-unused-variable */
|
||||
return this.blocks.filter((block, index) => index < this.numBlocks);
|
||||
/* tslint:enable:no-unused-variable */
|
||||
}
|
||||
|
||||
public goToBlocks(): void {
|
||||
this.navCtrl.push('blocks');
|
||||
}
|
||||
|
||||
private ngOnDestroy(): void {
|
||||
clearInterval(this.reloadInterval);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
<div>
|
||||
<div *ngIf="loading">
|
||||
<ion-spinner name="crescent"></ion-spinner>
|
||||
</div>
|
||||
|
||||
<div *ngIf="!loading">
|
||||
<ion-grid class="grid--table">
|
||||
|
||||
<ion-row>
|
||||
<ion-col><b>Hash</b></ion-col>
|
||||
<ion-col text-right><b>Value Out</b></ion-col>
|
||||
</ion-row>
|
||||
|
||||
<ion-row *ngFor="let tx of transactions">
|
||||
<ion-col col-9>
|
||||
<div class="ellipsis">
|
||||
<a (click)="goToTx(tx.txid)">{{ tx.txid }}</a>
|
||||
</div>
|
||||
</ion-col>
|
||||
<ion-col col-3 text-right>
|
||||
{{ currency.getConversion(tx.valueOut) }}
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
|
||||
</ion-grid>
|
||||
</div>
|
||||
</div>
|
||||
@ -0,0 +1,16 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { IonicModule } from 'ionic-angular';
|
||||
import { LatestTransactionsComponent } from './latest-transactions';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
LatestTransactionsComponent
|
||||
],
|
||||
imports: [
|
||||
IonicModule
|
||||
],
|
||||
exports: [
|
||||
LatestTransactionsComponent
|
||||
]
|
||||
})
|
||||
export class LatestTransactionsComponentModule {}
|
||||
@ -0,0 +1,2 @@
|
||||
latest-transactions {
|
||||
}
|
||||
@ -0,0 +1,65 @@
|
||||
import { Component, NgZone, Input } from '@angular/core';
|
||||
import { Http } from '@angular/http';
|
||||
import { NavController } from 'ionic-angular';
|
||||
import { ApiProvider } from '../../providers/api/api';
|
||||
import { CurrencyProvider } from '../../providers/currency/currency';
|
||||
|
||||
/**
|
||||
* Generated class for the LatestTransactionsComponent component.
|
||||
*
|
||||
* See https://angular.io/docs/ts/latest/api/core/index/ComponentMetadata-class.html
|
||||
* for more info on Angular Components.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'latest-transactions',
|
||||
templateUrl: 'latest-transactions.html'
|
||||
})
|
||||
export class LatestTransactionsComponent {
|
||||
|
||||
private loading: boolean = true;
|
||||
private transactions: Array<any> = [];
|
||||
@Input() public refreshSeconds: number = 10;
|
||||
private timer: number;
|
||||
|
||||
constructor(private http: Http, private navCtrl: NavController, private api: ApiProvider, public currency: CurrencyProvider, private ngZone: NgZone) {
|
||||
this.loadTransactions();
|
||||
}
|
||||
|
||||
public ngOnChanges(): void {
|
||||
if (this.timer) {
|
||||
clearInterval(this.timer);
|
||||
}
|
||||
|
||||
this.ngZone.runOutsideAngular(() => {
|
||||
this.timer = setInterval(
|
||||
function (): void {
|
||||
this.ngZone.run(function (): void {
|
||||
this.loadTransactions.call(this);
|
||||
}.bind(this));
|
||||
}.bind(this),
|
||||
1000 * this.refreshSeconds
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private loadTransactions(): void {
|
||||
let url: string = this.api.apiPrefix + 'txs';
|
||||
|
||||
this.http.get(url).subscribe(
|
||||
(data) => {
|
||||
this.transactions = JSON.parse(data['_body']);
|
||||
this.loading = false;
|
||||
},
|
||||
(err) => {
|
||||
console.log('err is', err);
|
||||
this.loading = false;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public goToTx(txId: string): void {
|
||||
this.navCtrl.push('transaction', {
|
||||
'txId': txId
|
||||
});
|
||||
}
|
||||
}
|
||||
14
app/src/components/transaction-list/transaction-list.html
Normal file
@ -0,0 +1,14 @@
|
||||
<div *ngIf="loading">
|
||||
<ion-spinner name="crescent"></ion-spinner>
|
||||
</div>
|
||||
|
||||
|
||||
<div *ngIf="!loading">
|
||||
<ion-grid>
|
||||
<ion-row *ngFor="let tx of transactions.txs">
|
||||
<ion-col col-12>
|
||||
<transaction [tx]="tx"></transaction>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
</div>
|
||||
@ -0,0 +1,18 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { IonicModule } from 'ionic-angular';
|
||||
import { TransactionListComponent } from './transaction-list';
|
||||
import { TransactionComponentModule } from '../transaction/transaction.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
TransactionListComponent
|
||||
],
|
||||
imports: [
|
||||
IonicModule,
|
||||
TransactionComponentModule
|
||||
],
|
||||
exports: [
|
||||
TransactionListComponent
|
||||
]
|
||||
})
|
||||
export class TransactionListComponentModule {}
|
||||
@ -0,0 +1,3 @@
|
||||
transaction-list {
|
||||
|
||||
}
|
||||
40
app/src/components/transaction-list/transaction-list.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Input } from '@angular/core';
|
||||
import { Http } from '@angular/http';
|
||||
import { ApiProvider } from '../../providers/api/api';
|
||||
|
||||
/**
|
||||
* Generated class for the TransactionListComponent component.
|
||||
*
|
||||
* See https://angular.io/docs/ts/latest/api/core/index/ComponentMetadata-class.html
|
||||
* for more info on Angular Components.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'transaction-list',
|
||||
templateUrl: 'transaction-list.html'
|
||||
})
|
||||
export class TransactionListComponent {
|
||||
|
||||
public loading: boolean = true;
|
||||
@Input() public queryType: string;
|
||||
@Input() public queryValue: string;
|
||||
public transactions: any = [];
|
||||
|
||||
constructor(private http: Http, private api: ApiProvider) {
|
||||
}
|
||||
|
||||
private ngOnInit(): void {
|
||||
let url: string = this.api.apiPrefix + 'txs?' + this.queryType + '=' + this.queryValue;
|
||||
|
||||
this.http.get(url).subscribe(
|
||||
(data) => {
|
||||
this.transactions = JSON.parse(data['_body']);
|
||||
this.loading = false;
|
||||
},
|
||||
(err) => {
|
||||
console.log('err is', err);
|
||||
this.loading = false;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||