diff --git a/.angular-cli.json b/.angular-cli.json index 20a8bec04..541bcce7c 100644 --- a/.angular-cli.json +++ b/.angular-cli.json @@ -19,10 +19,10 @@ "testTsconfig": "tsconfig.spec.json", "prefix": "app", "styles": [ - "../node_modules/bootstrap/dist/css/bootstrap.min.css", "../node_modules/font-awesome/css/font-awesome.min.css", "../node_modules/open-sans-all/css/open-sans.min.css", - "styles.scss" + "styles.scss", + "assets/theme.scss" ], "scripts": [ ], diff --git a/.editorconfig b/.editorconfig index 6e87a003d..3d2cbe21e 100644 --- a/.editorconfig +++ b/.editorconfig @@ -11,3 +11,11 @@ trim_trailing_whitespace = true [*.md] max_line_length = off trim_trailing_whitespace = false + + +[*.scss] +charset = utf-8 +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/main.js b/main.js index d2724e10d..22a038928 100644 --- a/main.js +++ b/main.js @@ -172,11 +172,7 @@ function makeTray() { // Set the tray icon tray.setToolTip('Particl ' + app.getVersion()); tray.setContextMenu(contextMenu) - - // Always show window when tray icon clicked - tray.on('click',function() { - mainWindow.show() - }); + return trayImage; } diff --git a/modules/rpc/daemon.js b/modules/rpc/daemon.js index 690f64084..eeefd61ad 100644 --- a/modules/rpc/daemon.js +++ b/modules/rpc/daemon.js @@ -28,8 +28,8 @@ function init(callback) { function startDaemon(restart, callback) { if (restart && daemon) { if (daemon.exitCode !== 0) { - setTimeout(() => startDaemon(restart, callback), 100); - return; + setTimeout(() => startDaemon(restart, callback), 200); + return false; } } @@ -40,22 +40,40 @@ function startDaemon(restart, callback) { waitForDaemon(callback); } }).catch(error => log.error(error)); + + return true; } function waitForDaemon(callback) { const maxRetries = 10; // Some slow computers... let retries = 0; + let errorString = ''; const daemonStartup = () => { rpc.checkDaemon(options) .then(callback) - .catch(() => retries < maxRetries && setTimeout(daemonStartup, 1000)); + .catch(() => !daemon.exitCode && retries < maxRetries && setTimeout(daemonStartup, 1000)); retries++; + if (daemon.exitCode || retries >= maxRetries) { - console.log(daemon.exitCode, retries); + // Rebuild block and transaction indexes + if (errorString.includes('-reindex')) { + log.info('Corrupted block database detected, ' + + 'restarting the daemon with the -reindex flag.'); + process.argv.push('-reindex'); + daemon.exitCode = 0; // Hack a bit here... + // We don't want it to exit at this stage if start was called.. + // it will probably error again if it has to. + if(startDaemon(true, callback)) { + return; + } + } electron.app.exit(991); } } if (daemon && !daemon.exitCode) { + daemon.stderr.on('data', data => { + errorString = data.toString('utf8'); + }); setTimeout(daemonStartup, 1000); } } diff --git a/modules/rpc/rpc.js b/modules/rpc/rpc.js index 8b93b11cd..1b24f9843 100644 --- a/modules/rpc/rpc.js +++ b/modules/rpc/rpc.js @@ -6,7 +6,7 @@ const rxIpc = require('rx-ipc-electron/lib/main').default; const cookie = require('./cookie'); const daemon = require('./daemon'); -let TIMEOUT = 10000; +let TIMEOUT = 15000; let HOSTNAME; let PORT; let rpcOptions; @@ -122,7 +122,7 @@ function init(options) { function checkDaemon(options) { return new Promise((resolve, reject) => { const _timeout = TIMEOUT; - TIMEOUT = 200; + TIMEOUT = 150; rpcCall( 'getnetworkinfo', null, cookie.getAuth(options), (error, response) => { rxIpc.removeListeners(); diff --git a/package.json b/package.json index 878cb67ae..6cb0f0515 100644 --- a/package.json +++ b/package.json @@ -82,11 +82,14 @@ }, "dependencies": { "@angular/animations": "^4.4.6", + "@angular/cdk": "2.0.0-beta.9", "@angular/common": "^4.4.6", "@angular/compiler": "^4.4.6", "@angular/core": "^4.4.6", + "@angular/flex-layout": "^2.0.0-beta.9", "@angular/forms": "^4.4.6", "@angular/http": "^4.4.6", + "@angular/material": "2.0.0-beta.9", "@angular/platform-browser": "^4.4.6", "@angular/platform-browser-dynamic": "^4.4.6", "@angular/router": "^4.4.6", @@ -98,7 +101,11 @@ "electron-log": "^2.2.10", "font-awesome": "^4.7.0", "got": "^7.1.0", + "hammerjs": "^2.0.8", "lodash": "^4.17.4", + "lodash.get": "^4.4.2", + "lodash.isempty": "^4.4.0", + "lodash.values": "^4.3.0", "ng2-logger": "^1.0.3", "ngx-bootstrap": "^1.8.0", "ngx-clipboard": "^8.0.3", diff --git a/src/app/app.component.controls.scss b/src/app/app.component.controls.scss index e5c65bb31..e77f2c0ac 100644 --- a/src/app/app.component.controls.scss +++ b/src/app/app.component.controls.scss @@ -1,3 +1,5 @@ +@import "./src/assets/_config"; // import shared colors etc. + :host /deep/ { button.control { border: 0; diff --git a/src/app/app.component.html b/src/app/app.component.html index 819d5bd88..cfe53a816 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1,91 +1,114 @@ - + + - - -
- - + -
-
- - - - - Overview - - - - - - Wallet - - - -
- - - Receive - - - - Send - - - - History - - - - Address Book - - - - Add account - -
- -
-
+ + - + + + + Wallet - -
- - - {{ title }} -
-
- + + + + + + Receive + + + + + + Send + + + + + + History + + + + + + Address Book + + + + + + Add Acount + + + + + + + + + + + + Settings + + + + + + + Settings + + + + + + + + + + + + error + {{daemonError}} + + + error + {{walletError}} + + + + + + + + + {{ title }} +
+
+ +
- +
- +
+ +
- - - + diff --git a/src/app/app.component.scss b/src/app/app.component.scss index 7791dafdc..55532b556 100644 --- a/src/app/app.component.scss +++ b/src/app/app.component.scss @@ -1,144 +1,73 @@ +@import "./src/assets/_config"; // import shared colors etc. + + +// ----------- GENERAL ----------- // + .center-vertical { position: relative; top: 50%; transform: translateY(-50%); } -.logo { - display: inline-block; - background-image: url("../assets/particl-logo.svg"); - background-repeat: no-repeat; - background-position: 0 0; - background-size: 120px 50px; - height: 50px; - width: 120px; -} -sidebar[position="left"] { - & { - background-color: #222828; - padding-left: 20px; - padding-right: 20px; - } - .full-width { - margin-left: -20px; - margin-right: -20px; +.mat-expansion-panel { // accordion submenu + border-bottom: 1px solid #15191A; + box-shadow: 0 1px 0 #333 !important; + .mat-expansion-panel-header { // submenu toggle + font-family: $font; + font-size: 11.5px; + color: #646869; + text-transform: uppercase; + padding: 0 24px 0 38px; } - hr { - @extend .full-width; - margin-top: 0; - margin-bottom: 0; - padding: 0; - border-top: 1px solid #191D1F; - border-bottom: 1px solid #272B2B; + .sidesubmenu { // submenu content + padding-top: 0; } - .header { - & { - @extend .full-width; - height: 100px; - text-align: center; - transform-style: preserve-3d; - } - .logo { - @extend .center-vertical; - } - .toggle-pinned { - cursor: pointer; - position: absolute; - top: 10px; - right: 20px; - color: #595D5E; - } +} + + +.mat-list { // menu item (whole) + .mat-list-item { + padding: 0 24px; } - .menu { - .item { - display: block; - text-decoration: none; - margin-left: -20px; - margin-right: -20px; - padding: 15px 20px; - color: #FFF; - text-transform: uppercase; - font-size: 11px; - font-weight: bold; - } - .icon { - color: #595D5E; - padding: 0 10px 0 10px; - } - .category { - & { - @extend .item; - color: #595D5E; - } - .icon { - padding: 0 0 0 10px; - float: right; - color: #00E8AF; - transition: all .2s ease; - } - .icon.collapsed { - transform: rotate(90deg); - } - } - .item.active .icon { - color: #00E8AF; - } + .mat-icon { // all icons in menu + margin: 8px 10px 0 0; + color: #4B4A4F; } - &.docked { - .header { - & { - text-align: right; - } - .logo { - width: 50px; - margin-right: 10px; - } - .toggle-pinned { - display: none; - } - } - .menu { - .icon, .category .icon { - float: right; - padding: 0 10px; - } - } + .menu-item { // menu-item (name only) + font-family: $font; + font-size: 11.5px; + font-weight: 600; + color: white; } } -sidebar[position="top"] { - & { - background-color: #FFF; - border-bottom: 1px solid #F2F2F2; - box-shadow: 0 0 1px #F2F2F2; - padding: 0 15px; - transform-style: preserve-3d; - } - .header { - & { - position: relative; - top: 50%; - transform: translateY(-50%); - color: #000; - text-transform: uppercase; - font-size: 12px; - } - a { - text-decoration: none; - color: inherit; - } - .icon { - vertical-align: middle; - } - * + * { - margin-left: 10px; - } - .toggle-menu { - cursor: pointer; - } +.mat-divider { // section divider + border-bottom: 1px solid #333; + border-top: 1px solid #15191A; +} + + +// ----------- SPECIFIC ----------- // + +.mat-sidenav { // nav container + width: 250px; + background-color: #222828; + color: #fff; + .mat-toolbar { + background: transparent; } } +.logo { + display: inline-block; + background-image: url("../assets/particl-logo.svg"); + background-repeat: no-repeat; + background-position: 0 0; + background-size: 144px 60px; + height: 60px; + width: 144px; +} + /deep/ .verify-sucess { color: #4F8A10; background-color: #DFF2BF !important; diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts index 657749fb4..cf71faa5c 100644 --- a/src/app/app.component.spec.ts +++ b/src/app/app.component.spec.ts @@ -53,11 +53,11 @@ let component: AppComponent; })); */ it('should get isCollapsed', () => { - expect(component.isCollapsed).toBe(true); + expect(component.isCollapsed).toBeTruthy() }); it('should get isFixed', () => { - expect(component.isFixed).toBe(false); + expect(component.isFixed).toBeFalsy(); }); it('should get log', () => { diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 1d48f1a9b..5a02ca02f 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,13 +1,19 @@ import { Component, OnInit } from '@angular/core'; import { Router, ActivatedRoute, NavigationEnd } from '@angular/router'; import { Log } from 'ng2-logger'; +import { MdDialog, MdIconRegistry } from '@angular/material'; import { WindowService } from './core/window.service'; import { SettingsService } from './settings/settings.service'; +import { RPCService } from './core/rpc/rpc.service'; import { ModalsService } from './modals/modals.service'; +// Syncing example +import { BlockStatusService } from './core/rpc/blockstatus.service'; +import { ModalsComponent } from './modals/modals.component'; + @Component({ selector: 'app-root', templateUrl: './app.component.html', @@ -21,14 +27,23 @@ export class AppComponent implements OnInit { isFixed: boolean = false; title: string = ''; log: any = Log.create('app.component'); - + walletInitialized: boolean = false; + daemonRunning: boolean = false; + daemonError: string = ''; + walletError: string = ''; constructor( private _router: Router, private _route: ActivatedRoute, public window: WindowService, - // Modal example - private _modalsService: ModalsService + private _rpc: RPCService, + private _modalsService: ModalsService, + private dialog: MdDialog, + private iconRegistry: MdIconRegistry ) { + + iconRegistry + .registerFontClassAlias('ncIcon', 'nc-icon') + .registerFontClassAlias('faIcon', 'fa'); } ngOnInit() { @@ -51,10 +66,23 @@ export class AppComponent implements OnInit { this.log.w('warn!'); this.log.i('info'); this.log.d('debug'); + + this._rpc.modalUpdates.asObservable().subscribe(status => { + this.daemonRunning = !status.error; + this.daemonError = this.daemonRunning ? '' : 'Connection Refused, Daemon is not connected'; + }); + + this._rpc.state.observe('walletInitialized') + .subscribe( + status => { + this.walletInitialized = status; + this.walletError = status ? '' : 'Please create wallet first to access other tabs'; + }); } createWallet() { + // this.dialog.open(ModalsComponent, {disableClose: true, width: '100%', height: '100%'}); this._modalsService.open('createWallet', {forceOpen: true}); } } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 6e9f303ff..cd195e5fc 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -1,9 +1,17 @@ import { BrowserModule } from '@angular/platform-browser'; -import { NgModule } from '@angular/core'; +import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { RouterModule, Routes } from '@angular/router'; -import { BsDropdownModule, CollapseModule, ModalModule, ModalDirective, PaginationModule, TooltipModule } from 'ngx-bootstrap'; +import { + MdButtonModule, MdCardModule, MdCheckboxModule, MdExpansionModule, MdGridListModule, MdIconModule, MdListModule, + MdMenuModule, + MdProgressBarModule, + MdSidenavModule, + MdSnackBarModule, MdTabsModule, MdToolbarModule, + MdTooltipModule +} from '@angular/material'; +import { FlexLayoutModule } from '@angular/flex-layout'; import { SharedModule } from './shared/shared.module'; import { SidebarModule } from './core/sidebar/sidebar.module'; @@ -19,6 +27,12 @@ import { AppComponent } from './app.component'; import { StatusComponent } from './core/status/status.component'; import { OverviewComponent } from './overview/overview.component'; import { SettingsComponent } from './settings/settings.component'; +import { StakinginfoComponent } from './overview/widgets/stakinginfo/stakinginfo.component'; + +import 'hammerjs'; +import { FlashNotificationService } from './services/flash-notification.service'; +import { BlockStatusService } from './core/rpc/blockstatus.service'; +import { ColdstakeComponent } from './overview/widgets/coldstake/coldstake.component'; const routes: Routes = [ { path: 'overview', component: OverviewComponent, data: { title: 'Overview' } }, @@ -31,7 +45,9 @@ const routes: Routes = [ AppComponent, StatusComponent, OverviewComponent, - SettingsComponent + SettingsComponent, + StakinginfoComponent, + ColdstakeComponent ], imports: [ BrowserModule, @@ -41,12 +57,30 @@ const routes: Routes = [ SidebarModule.forRoot(), WalletModule.forRoot(), RpcModule.forRoot(), - ModalsModule + ModalsModule, + MdButtonModule, + MdCheckboxModule, + MdListModule, + MdExpansionModule, + FlexLayoutModule, + MdTooltipModule, + MdSnackBarModule, + MdMenuModule, + MdProgressBarModule, + MdIconModule, + MdSidenavModule, + MdGridListModule, + MdCardModule, + MdToolbarModule ], providers: [ + WindowService, + BlockStatusService, + FlashNotificationService, WindowService ], - bootstrap: [ AppComponent ] + bootstrap: [ AppComponent ], + schemas: [CUSTOM_ELEMENTS_SCHEMA] }) export class AppModule { diff --git a/src/app/core/rpc/rpc-state.class.ts b/src/app/core/rpc/rpc-state.class.ts index c602ede5b..846cba62a 100644 --- a/src/app/core/rpc/rpc-state.class.ts +++ b/src/app/core/rpc/rpc-state.class.ts @@ -1,6 +1,10 @@ +import { Log } from 'ng2-logger'; import { RPCService } from './rpc.service'; + export class RPCStateClass { + private log: any = Log.create('rpc-state.class'); + constructor(private rpc: RPCService) { // Start polling... @@ -12,6 +16,7 @@ export class RPCStateClass { this.lastBlockTimeState(); this.blockLoop(); this.walletLockedState(); + this.initWalletState(); } private lastBlockTimeState() { @@ -43,4 +48,30 @@ export class RPCStateClass { .subscribe(status => this.rpc.state .set('locked', ['Locked', 'Unlocked, staking only'].includes(status))); } + + private initWalletState() { + + this.rpc.state.observe('encryptionstatus').take(1) + .subscribe( + status => { + const locked = this.rpc.state.get('locked'); + + if (locked) { + this.rpc.state.set('walletInitialized', true); + return; + } + + this.rpc.call('extkey', ['list']) + .subscribe( + response => { + // check if account is active + if (response.result === 'No keys to list.') { + this.rpc.state.set('walletInitialized', false); + } else { + this.rpc.state.set('walletInitialized', true); + } + }, + error => this.log.er('RPC Call returned an error', error)); + }); + } } diff --git a/src/app/core/status/status.component.html b/src/app/core/status/status.component.html index 263c92a12..78963784d 100644 --- a/src/app/core/status/status.component.html +++ b/src/app/core/status/status.component.html @@ -1,40 +1,24 @@ - - Peers: {{ peerListCount }} - - - - {{ encryptionStatus }} - - - - Cold - - - - + + - + - - + + diff --git a/src/app/core/status/status.component.spec.ts b/src/app/core/status/status.component.spec.ts index 503ffe9a5..8e0e99a3a 100644 --- a/src/app/core/status/status.component.spec.ts +++ b/src/app/core/status/status.component.spec.ts @@ -1,11 +1,11 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { TooltipModule } from 'ngx-bootstrap'; import { StatusComponent } from './status.component'; import { ModalsModule } from '../../modals/modals.module'; import { SharedModule } from '../../shared/shared.module'; import { RpcModule } from '../rpc/rpc.module'; +import { MdTooltipModule } from '@angular/material'; describe('StatusComponent', () => { let component: StatusComponent; @@ -15,10 +15,10 @@ describe('StatusComponent', () => { TestBed.configureTestingModule({ declarations: [ StatusComponent ], imports: [ - SharedModule, - RpcModule.forRoot(), - TooltipModule.forRoot(), - ModalsModule + SharedModule, + RpcModule.forRoot(), + ModalsModule, + MdTooltipModule ] }) .compileComponents(); diff --git a/src/app/core/status/status.component.ts b/src/app/core/status/status.component.ts index 7964240b6..a520de133 100644 --- a/src/app/core/status/status.component.ts +++ b/src/app/core/status/status.component.ts @@ -5,7 +5,8 @@ import { Log } from 'ng2-logger'; import { ModalsService } from '../../modals/modals.service'; import { StateService } from '../state/state.service'; -import { PeerService, RPCService, BlockStatusService } from '../rpc/rpc.module'; +import { RPCService } from '../rpc/rpc.module'; +import { MdDialog} from '@angular/material'; @Component({ selector: 'app-status', @@ -82,6 +83,6 @@ export class StatusComponent implements OnInit { } openColdStakeModal() { - this._modalsService.open('coldStake', {forceOpen: true}); + this._modalsService.open('coldStake', {'forceOpen': true}); } } diff --git a/src/app/layouts/layouts.module.spec.ts b/src/app/layouts/layouts.module.spec.ts new file mode 100644 index 000000000..0a94a0ebd --- /dev/null +++ b/src/app/layouts/layouts.module.spec.ts @@ -0,0 +1,13 @@ +import { LayoutsModule } from './layouts.module'; + +describe('LayoutsModule', () => { + let layoutsModule: LayoutsModule; + + beforeEach(() => { + layoutsModule = new LayoutsModule(); + }); + + it('should create an instance', () => { + expect(layoutsModule).toBeTruthy(); + }); +}); diff --git a/src/app/layouts/layouts.module.ts b/src/app/layouts/layouts.module.ts new file mode 100644 index 000000000..4c8777875 --- /dev/null +++ b/src/app/layouts/layouts.module.ts @@ -0,0 +1,26 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { LayoutSideNavComponent } from './side-nav/side-nav.component'; +import { MdDialogModule, MdExpansionModule } from '@angular/material'; +import { FlexLayoutModule } from '@angular/flex-layout'; +import { ModalsService } from '../modals/modals.service'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; + +@NgModule({ + imports: [ + CommonModule, + MdDialogModule, + FlexLayoutModule, + MdExpansionModule, + BrowserAnimationsModule + ], + declarations: [LayoutSideNavComponent], + exports: [ + LayoutSideNavComponent + ], + providers: [ + ModalsService + ] +}) +export class LayoutsModule { +} diff --git a/src/app/layouts/side-nav/side-nav.component.css b/src/app/layouts/side-nav/side-nav.component.css new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/layouts/side-nav/side-nav.component.html b/src/app/layouts/side-nav/side-nav.component.html new file mode 100644 index 000000000..bd74addf9 --- /dev/null +++ b/src/app/layouts/side-nav/side-nav.component.html @@ -0,0 +1,42 @@ + + + Wallet + + + + + diff --git a/src/app/layouts/side-nav/side-nav.component.spec.ts b/src/app/layouts/side-nav/side-nav.component.spec.ts new file mode 100644 index 000000000..97550efd4 --- /dev/null +++ b/src/app/layouts/side-nav/side-nav.component.spec.ts @@ -0,0 +1,41 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { LayoutSideNavComponent } from './side-nav.component'; +import { MdDialog, MdDialogModule, MdExpansionModule, MdIconModule } from '@angular/material'; +import { ModalsService} from '../../modals/modals.service'; +import { BlockStatusService } from '../../core/rpc/blockstatus.service'; +import { PeerService } from '../../core/rpc/peer.service'; +import { RpcModule } from '../../core/rpc/rpc.module'; +import { SharedModule } from '../../shared/shared.module'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; + +describe('LayoutSideNavComponent', () => { + let component: LayoutSideNavComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + SharedModule, + MdExpansionModule, + MdIconModule, + MdDialogModule, + RpcModule.forRoot(), + BrowserAnimationsModule + ], + providers: [ MdDialog, ModalsService, BlockStatusService, PeerService ], + declarations: [ LayoutSideNavComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(LayoutSideNavComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/layouts/side-nav/side-nav.component.ts b/src/app/layouts/side-nav/side-nav.component.ts new file mode 100644 index 000000000..6a74799e3 --- /dev/null +++ b/src/app/layouts/side-nav/side-nav.component.ts @@ -0,0 +1,25 @@ +import { Component, OnInit } from '@angular/core'; +import { ModalsComponent } from '../../modals/modals.component'; +import { MdDialog } from '@angular/material'; +import { ModalsService } from '../../modals/modals.service'; + +@Component({ + selector: 'app-side-nav', + templateUrl: './side-nav.component.html', + styleUrls: ['./side-nav.component.css'] +}) +export class LayoutSideNavComponent implements OnInit { + + constructor(private dialog: MdDialog, + private _modalsService: ModalsService) { + } + + ngOnInit() { + } + + createWallet() { + // this.dialog.open(ModalsComponent, {disableClose: true, width: '100%', height: '100%'}); + // this._modalsService.open('createWallet', {forceOpen: true}); + } + +} diff --git a/src/app/modals/coldstake/coldstake.component.html b/src/app/modals/coldstake/coldstake.component.html index 6ccbe17c1..558339ba5 100644 --- a/src/app/modals/coldstake/coldstake.component.html +++ b/src/app/modals/coldstake/coldstake.component.html @@ -1,32 +1,29 @@
-
-

Welcome, read the instructions very carefully!

-

- Hot wallet: - Selecting this option will turn this computer into a staking node. - It will be unable to spend the coins but is allowed to stake them.
-

-

- Cold wallet: - Selecting this option will turn this computer into a cold storage node. - It is able to spend the coins but is not allowed to stake them.
- Note: this will create a special transaction with a dust output of 0.00001 and a transaction fee. -

-
- -
+
+
+

Welcome, read the instructions very carefully!

+

+ Hot wallet: + Selecting this option will turn this computer into a staking node. + It will be unable to spend the coins but is allowed to stake them.
+

+

+ Cold wallet: + Selecting this option will turn this computer into a cold storage node. + It is able to spend the coins but is not allowed to stake them.
+ Note: this will create a special transaction with a dust output of 0.00001 and a transaction fee. +

+
-
-
-
- -
-
-
@@ -36,90 +33,98 @@ - - - - -
- +
+ + + +
+
+ +
+
-
+
+

Hot wallet: Copy this and enter this into the cold wallet.

-
+
-
-
- +
+
+ + +
-
- +
+
-
-
- -
-
-
+
-
+
+

Please enter the address generated by the hot wallet.

-
+
-
+
-
- +
+ + +
-
+
-
-
- +
-
-

+

+
{{finalMessage}} -

+
diff --git a/src/app/modals/coldstake/coldstake.component.scss b/src/app/modals/coldstake/coldstake.component.scss index 3c66ccdcb..bbf357734 100644 --- a/src/app/modals/coldstake/coldstake.component.scss +++ b/src/app/modals/coldstake/coldstake.component.scss @@ -1,12 +1,5 @@ -.icon { - padding: 7px 2px; -} -.red-bg { - background-color: red !important; -} - -.blue-bg { - background-color: #00d2ff !important; +.input-gap { + margin: 12px !important; } @media only screen and (max-width: 480px) { diff --git a/src/app/modals/coldstake/coldstake.component.spec.ts b/src/app/modals/coldstake/coldstake.component.spec.ts index 95f57ae55..f78571d28 100644 --- a/src/app/modals/coldstake/coldstake.component.spec.ts +++ b/src/app/modals/coldstake/coldstake.component.spec.ts @@ -6,6 +6,7 @@ import { RpcModule } from '../../core/rpc/rpc.module'; import { ModalsModule } from '../modals.module'; import { ColdstakeComponent } from './coldstake.component'; +import { MdDialogRef } from '@angular/material'; describe('ColdstakeComponent', () => { let component: ColdstakeComponent; @@ -18,6 +19,9 @@ describe('ColdstakeComponent', () => { SharedModule, RpcModule.forRoot(), ModalsModule + ], + providers: [ + { provide: MdDialogRef} ] }) .compileComponents(); diff --git a/src/app/modals/coldstake/coldstake.component.ts b/src/app/modals/coldstake/coldstake.component.ts index 5a0cc81bc..1f00f3181 100644 --- a/src/app/modals/coldstake/coldstake.component.ts +++ b/src/app/modals/coldstake/coldstake.component.ts @@ -7,6 +7,8 @@ import { ModalsService } from '../modals.service'; import { RPCService } from '../../core/rpc/rpc.module'; import { PasswordComponent } from '../shared/password/password.component'; +import { MdDialogRef } from '@angular/material'; +import { ModalsComponent } from '../modals.component'; @Component({ selector: 'app-coldstake', @@ -39,7 +41,8 @@ export class ColdstakeComponent { constructor( @Inject(forwardRef(() => ModalsService)) private _modalsService: ModalsService, - private _rpc: RPCService + private _rpc: RPCService, + public dialogRef: MdDialogRef ) { } nextStep () { @@ -164,8 +167,7 @@ export class ColdstakeComponent { } close() { - const escape = new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }); - document.body.dispatchEvent(escape); + this.dialogRef.componentInstance.close(); } /** diff --git a/src/app/modals/createwallet/createwallet.component.html b/src/app/modals/createwallet/createwallet.component.html index 8acf77c1a..92d6b3174 100644 --- a/src/app/modals/createwallet/createwallet.component.html +++ b/src/app/modals/createwallet/createwallet.component.html @@ -1,159 +1,154 @@
-
- Welcome, please select one of the options below. - -
- It is recommended to encrypt your wallet before creating or restoring a wallet, in order to not leave any possible key fragments lying around. -
-
- -
- -
-
-
- -
-
- -
-
- +
+
+ Welcome, please select one of the options below. +
+ It is recommended to encrypt your wallet before creating or restoring a wallet, in order to not leave any + possible key fragments lying around.
+
+ +
+ + + +
-
- Lets create a new wallet -
- -
- -
- -
-
- +
+
+ Let's create a new wallet
-
-
- + -
-
- Wallet Name is required +
+ + +
+
+
-
- Wallet Name cannot be more than 32 characters long. + +
+
+ + + + +
+
+ Wallet Name is required +
+
+ Wallet Name cannot be more than 32 characters long. +
+
+
+
+ + +
-
-
-
- -
-
-
- -
-
- -
+
- -
- +
+ +
+ Generate your wallet recovery phrase - - Write down your wallet recovery phrase
-
+ + Write down your wallet recovery phrase
+
It is very important to write down your recovery phrase and to remember your password. You will not be able to restore your wallet without them.
- - Enter your wallet recovery phrase
+ + Enter your wallet recovery phrase
Fill in the missing words of the recovery passphrase.
-
-
- -
-
- +
+
+
+
+ +
-
-
- +
+
+ + + +
+
-
- - + - - + + - - -
- {{ errorString }} -
- -
-
-
- + +
+
+ {{ errorString }}
-
- +
@@ -161,81 +156,94 @@ -
+
+
Please enter your 24 word recovery phrase and optional recovery passphrase below. -
-
- -
-
- +
+
+
+
+ +
-
-
- +
+
+ + + +
+
-
- -
+ - + -
- {{ errorString }} -
+
+ {{ errorString }} +
- + -
-
-
- -
+
+
+
+
+ +
+
+
-
-
-
-

Congratulations with your new wallet

-
- Your new wallet has been set as the default wallet, you can new generate new addresses on your wallet. -
+
+
+

Congratulations with your new wallet

+
+ Your new wallet has been set as the default wallet, you can now generate new addresses on your wallet.
-
+
-
- -
- +
+
+ +
+
- - +
+ + + + + + + +
diff --git a/src/app/modals/createwallet/createwallet.component.scss b/src/app/modals/createwallet/createwallet.component.scss index 5e6d49b4c..eaf6c43be 100644 --- a/src/app/modals/createwallet/createwallet.component.scss +++ b/src/app/modals/createwallet/createwallet.component.scss @@ -1,17 +1,34 @@ /deep/ app-password > div { - margin-top: 20px; + margin-top: 20px; } /deep/ input.recovery-word { - max-width: 100%; + max-width: 100%; } .alert { - margin-bottom: 0; + margin-bottom: 0; +} + +.align-center { + text-align: center; +} + +.create-wallet-action-button { + margin: 3px; +} + +.mat-dialog-content { + width: 100% !important; + height: 100% !important; +} + +.gap50 { + height: 50px; } @media only screen and (max-width: 480px) { - .wallet-buttons-container button{ + .wallet-buttons-container button { float: none; display: block; margin: 10px auto 0; diff --git a/src/app/modals/createwallet/createwallet.component.ts b/src/app/modals/createwallet/createwallet.component.ts index 2e6ad9bbb..e39420c91 100644 --- a/src/app/modals/createwallet/createwallet.component.ts +++ b/src/app/modals/createwallet/createwallet.component.ts @@ -55,6 +55,7 @@ export class CreateWalletComponent { reset() { this._modalsService.enableClose = true; + this.state.set('modal:fullWidth:enableClose', true); this.words = Array(24).fill(''); this.isRestore = false; this.name = ''; @@ -137,6 +138,7 @@ export class CreateWalletComponent { break; } this._modalsService.enableClose = (this.step === 0); + this.state.set('modal:fullWidth:enableClose', (this.step === 0)); } private mnemonicCallback(response: Object) { @@ -156,12 +158,14 @@ export class CreateWalletComponent { success => { this.animationState = 'next'; this.step = 5; + this.state.set('activeWallet', true); this.log.i('Mnemonic imported successfully'); }, error => { this.log.er(error); this.errorString = error.message; this._modalsService.enableClose = true; + this.state.set('modal:fullWidth:enableClose', true); this.log.er('Mnemonic import failed'); }); } diff --git a/src/app/modals/createwallet/passphrase/passphrase.component.html b/src/app/modals/createwallet/passphrase/passphrase.component.html index 43909e8ef..61ae5bf46 100644 --- a/src/app/modals/createwallet/passphrase/passphrase.component.html +++ b/src/app/modals/createwallet/passphrase/passphrase.component.html @@ -1,69 +1,33 @@ - - - - - -
-
- -
-
-
- -
-
- - -
-
-
+
diff --git a/src/app/modals/createwallet/passphrase/passphrase.component.spec.ts b/src/app/modals/createwallet/passphrase/passphrase.component.spec.ts index 980cf5b1e..ab60a6fa3 100644 --- a/src/app/modals/createwallet/passphrase/passphrase.component.spec.ts +++ b/src/app/modals/createwallet/passphrase/passphrase.component.spec.ts @@ -8,6 +8,9 @@ import { PassphraseService } from './passphrase.service'; import { FormsModule } from '@angular/forms'; import { FocusDirective } from '../../modals.directives'; import { PassphraseComponent } from './passphrase.component'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { MdDialogRef, MdIconModule, MdInputModule, MdSnackBarModule } from '@angular/material'; +import { FlashNotificationService } from '../../../services/flash-notification.service'; describe('PassphraseComponent', () => { @@ -19,13 +22,20 @@ describe('PassphraseComponent', () => { imports: [ FormsModule, SharedModule, - RpcModule.forRoot() + RpcModule.forRoot(), + BrowserAnimationsModule, + MdIconModule, + MdSnackBarModule ], declarations: [ FocusDirective, PassphraseComponent ], - providers: [PassphraseService] + providers: [ + { provide: MdDialogRef}, + PassphraseService, + FlashNotificationService + ] }) .compileComponents(); })); diff --git a/src/app/modals/createwallet/passphrase/passphrase.component.ts b/src/app/modals/createwallet/passphrase/passphrase.component.ts index 72fbfa00f..96b85386f 100644 --- a/src/app/modals/createwallet/passphrase/passphrase.component.ts +++ b/src/app/modals/createwallet/passphrase/passphrase.component.ts @@ -4,6 +4,7 @@ import { ClipboardModule } from 'ngx-clipboard'; import { PassphraseService } from './passphrase.service'; import { Log } from 'ng2-logger'; +import { FlashNotificationService } from '../../../services/flash-notification.service'; const MAX_WORDS = 24; @@ -24,13 +25,17 @@ export class PassphraseComponent implements OnChanges { @Input() readOnly: boolean = false; @Input() isDisabled: boolean = false; @Input() partialDisable: boolean = false; + @Input() generate: boolean = false; @Output() wordsEmitter: EventEmitter = new EventEmitter(); @Output() seedImportedSuccesfulEmitter: EventEmitter = new EventEmitter(); log: any = Log.create('passphrase.component'); - constructor (private _passphraseService: PassphraseService) {} + constructor( + private _passphraseService: PassphraseService, + private flashNotificationService: FlashNotificationService) { + } ngOnChanges(): void { this.editable = []; @@ -75,4 +80,8 @@ export class PassphraseComponent implements OnChanges { clear() { this.words = Array(MAX_WORDS).fill(''); } + + copyToClipBoard(): void { + this.flashNotificationService.open('Wallet recovery phrase copied to clipboard.', '', 1000); + } } diff --git a/src/app/modals/daemon/daemon.component.ts b/src/app/modals/daemon/daemon.component.ts index 7c44eb39f..dee5038b3 100644 --- a/src/app/modals/daemon/daemon.component.ts +++ b/src/app/modals/daemon/daemon.component.ts @@ -1,6 +1,4 @@ -import { Component, Inject, forwardRef } from '@angular/core'; - -import { ModalsService } from '../modals.service'; +import { Component } from '@angular/core'; @Component({ selector: 'app-daemon', diff --git a/src/app/modals/encryptwallet/encryptwallet.component.html b/src/app/modals/encryptwallet/encryptwallet.component.html index 69d3ba28e..abca03888 100644 --- a/src/app/modals/encryptwallet/encryptwallet.component.html +++ b/src/app/modals/encryptwallet/encryptwallet.component.html @@ -1,19 +1,15 @@ -
-
-
+
+
+

Please enter a password to encrypt your wallet.

Do NOT forget this password or you will be unable to access your coins.

-
+

Please enter your password again to confirm that you've typed the right password.

Do NOT forget this password or you will be unable to access your coins.

-
-
- -
Do NOT forget this password or you will be unable to access your coins. -
-
-
- -
+
+
+
- - - \ No newline at end of file +
+ diff --git a/src/app/modals/encryptwallet/encryptwallet.component.spec.ts b/src/app/modals/encryptwallet/encryptwallet.component.spec.ts index cab329f9c..771eb083e 100644 --- a/src/app/modals/encryptwallet/encryptwallet.component.spec.ts +++ b/src/app/modals/encryptwallet/encryptwallet.component.spec.ts @@ -5,6 +5,7 @@ import { RpcModule } from '../../core/rpc/rpc.module'; import { EncryptwalletComponent } from './encryptwallet.component'; import { ModalsModule } from '../modals.module'; +import { MdSnackBarModule } from '@angular/material'; describe('EncryptwalletComponent', () => { @@ -16,7 +17,8 @@ describe('EncryptwalletComponent', () => { imports: [ SharedModule, ModalsModule, - RpcModule.forRoot() + RpcModule.forRoot(), + MdSnackBarModule ] }) .compileComponents(); diff --git a/src/app/modals/encryptwallet/encryptwallet.component.ts b/src/app/modals/encryptwallet/encryptwallet.component.ts index 26b86bfb8..5ea6982b0 100644 --- a/src/app/modals/encryptwallet/encryptwallet.component.ts +++ b/src/app/modals/encryptwallet/encryptwallet.component.ts @@ -1,14 +1,11 @@ -import { - Component, ComponentRef, Inject, - forwardRef, ElementRef, ViewChild -} from '@angular/core'; +import {Component, forwardRef, Inject, ViewChild} from '@angular/core'; import { Log } from 'ng2-logger'; -import { ModalsService } from 'app/modals/modals.service'; import { RPCService } from '../../core/rpc/rpc.module'; import { PasswordComponent } from '../shared/password/password.component'; -import { AlertComponent } from '../shared/alert/alert.component'; import { IPassword } from '../shared/password/password.interface'; +import { FlashNotificationService } from '../../services/flash-notification.service'; +import { ModalsService } from '../modals.service'; @Component({ selector: 'app-encryptwallet', @@ -23,13 +20,11 @@ export class EncryptwalletComponent { @ViewChild('passwordElement') passwordElement: PasswordComponent; - @ViewChild('alertBox') - alertBox: AlertComponent; - - constructor( - private _rpc: RPCService, - @Inject(forwardRef(() => ModalsService)) - private _modalsService: ModalsService) { } + constructor(private _rpc: RPCService, + private flashNotification: FlashNotificationService, + @Inject(forwardRef(() => ModalsService)) + private _modalsService: ModalsService) { + } encryptwallet(password: IPassword) { if (this.password) { @@ -43,7 +38,7 @@ export class EncryptwalletComponent { .subscribe( response => { this._rpc.toggleState(false); - this.alertBox.open(response, 'Wallet'); + this.flashNotification.open(response); if (this._rpc.isElectron) { this._rpc.call('restart-daemon') @@ -59,11 +54,11 @@ export class EncryptwalletComponent { }, // Handle error appropriately error => { - this.alertBox.open('Wallet failed to encrypt properly!', 'Wallet'); + this.flashNotification.open('Wallet failed to encrypt properly!'); this.log.er('error encrypting wallet', error) }); } else { - this.alertBox.open('The passwords do not match!', 'Wallet'); + this.flashNotification.open('The passwords do not match!'); } } else { diff --git a/src/app/modals/modals.component.html b/src/app/modals/modals.component.html index bb81816ab..a8a67cbbd 100644 --- a/src/app/modals/modals.component.html +++ b/src/app/modals/modals.component.html @@ -1,29 +1,13 @@ -