latest GUI source

This commit is contained in:
wildkif 2019-01-09 15:31:41 +02:00
parent 120f67f331
commit d6a3bd8b65
61 changed files with 666 additions and 319 deletions

View file

@ -24,7 +24,8 @@
"tsConfig": "src/tsconfig.app.json",
"assets": [
"src/favicon.ico",
"src/assets"
"src/assets",
"src/files"
],
"styles": [
"src/styles.scss"

View file

@ -1,11 +1,11 @@
<div class="modal">
<div class="content">
<i class="icon"></i>
<div class="message">
<span>Success</span>
<span>Successfully</span>
<i class="icon" [class.error]="type === 'error'" [class.success]="type === 'success'" [class.info]="type === 'info'"></i>
<div class="message-container">
<span class="title">{{title}}</span>
<span class="message">{{message}}</span>
</div>
</div>
<button type="button" class="action-button" (click)="false">OK</button>
<button type="button" class="close-button" (click)="false"><i class="icon close"></i></button>
<button type="button" class="action-button" (click)="onClose()" #btn>OK</button>
<button type="button" class="close-button" (click)="onClose()"><i class="icon close"></i></button>
</div>

View file

@ -13,28 +13,53 @@
position: relative;
display: flex;
flex-direction: column;
background-position: center;
background-size: 200%;
padding: 2rem;
width: 34rem;
background: #1a1a1a;
.content {
display: flex;
margin: 1.2rem 0;
.icon {
flex: 0 0 auto;
width: 4.4rem;
height: 4.4rem;
&.error {
mask: url(~src/assets/icons/modal-alert.svg) no-repeat center;
}
&.success {
mask: url(~src/assets/icons/modal-success.svg) no-repeat center;
}
&.info {
mask: url(~src/assets/icons/modal-info.svg) no-repeat center;
}
}
.message {
.message-container {
display: flex;
flex-direction: column;
margin-left: 2rem;
.title {
font-size: 1.8rem;
font-weight: 600;
line-height: 2.2rem;
}
.message {
font-size: 1.3rem;
line-height: 1.8rem;
margin-top: 0.4rem;
}
}
}
.action-button {
background: #2c95f1;
margin: 1.2rem auto 0.6rem;
width: 10rem;
height: 2.4rem;
@ -42,15 +67,21 @@
.close-button {
position: absolute;
top: 0.5rem;
right: 0.5rem;
top: 0;
right: 0;
display: flex;
align-items: center;
justify-content: center;
background: transparent;
margin: 0;
padding: 0;
width: 1.5rem;
height: 1.5rem;
width: 2.4rem;
height: 2.4rem;
.icon {
mask: url(~src/assets/icons/close.svg) no-repeat center;
width: 2.4rem;
height: 2.4rem;
}
}
}

View file

@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core';
import {Component, OnInit, Input, Output, EventEmitter, ViewChild, ElementRef} from '@angular/core';
@Component({
selector: 'app-modal-container',
@ -7,9 +7,25 @@ import { Component, OnInit } from '@angular/core';
})
export class ModalContainerComponent implements OnInit {
constructor() { }
public title: string;
@Input() type: string;
@Input() message: string;
@Output() close = new EventEmitter<boolean>();
@ViewChild('btn') button: ElementRef;
constructor() {}
ngOnInit() {
this.button.nativeElement.focus();
switch (this.type) {
case 'error': this.title = 'Wrong'; break;
case 'success': this.title = 'Success'; break;
case 'info': this.title = 'Information'; break;
default: this.title = 'Unexpected'; break;
}
}
onClose() {
this.close.emit();
}
}

View file

@ -13,11 +13,9 @@ export class StakingSwitchComponent implements OnInit {
@Input() staking: boolean;
@Output() stakingChange = new EventEmitter<boolean>();
constructor(private backend: BackendService, private variablesService: VariablesService) {
}
constructor(private backend: BackendService, private variablesService: VariablesService) {}
ngOnInit() {
}
ngOnInit() {}
toggleStaking() {
const wallet = this.variablesService.getWallet(this.wallet_id);

View file

@ -1,28 +1,36 @@
import {Directive, Input, ElementRef, HostListener, Renderer2} from '@angular/core';
import {Directive, Input, ElementRef, HostListener, Renderer2, HostBinding} from '@angular/core';
@Directive({
selector: '[tooltip]',
host: {
'[style.cursor]': '"pointer"'
}
selector: '[tooltip]'
})
export class TooltipDirective {
@HostBinding('style.cursor') cursor = 'pointer';
@Input('tooltip') tooltipTitle: string;
@Input() placement: string;
@Input() tooltipClass: string;
@Input() delay: number;
tooltip: HTMLElement;
offset = 10;
constructor(private el: ElementRef, private renderer: Renderer2) {}
removeTooltipTimeout;
constructor(private el: ElementRef, private renderer: Renderer2) {
}
@HostListener('mouseenter') onMouseEnter() {
if (!this.tooltip) { this.show(); }
if (!this.tooltip) {
this.show();
} else {
this.cancelHide();
}
}
@HostListener('mouseleave') onMouseLeave() {
if (this.tooltip) { this.hide(); }
if (this.tooltip) {
this.hide();
}
}
show() {
@ -32,12 +40,17 @@ export class TooltipDirective {
hide() {
this.renderer.setStyle(this.tooltip, 'opacity', '0');
window.setTimeout(() => {
this.removeTooltipTimeout = setTimeout(() => {
this.renderer.removeChild(document.body, this.tooltip);
this.tooltip = null;
}, this.delay);
}
cancelHide() {
clearTimeout(this.removeTooltipTimeout);
this.renderer.setStyle(this.tooltip, 'opacity', '1');
}
create() {
this.tooltip = this.renderer.createElement('span');
this.renderer.appendChild(this.tooltip, this.renderer.createText(this.tooltipTitle));
@ -76,8 +89,15 @@ export class TooltipDirective {
}
if (this.placement === 'bottom') {
this.renderer.setStyle(this.tooltip, 'top', hostPos.bottom + 'px');
this.renderer.setStyle(this.tooltip, 'left', hostPos.left + 'px');
if (window.innerHeight < hostPos.bottom + this.tooltip.offsetHeight + parseInt(getComputedStyle(this.tooltip).marginTop, 10)) {
this.renderer.removeClass(this.tooltip, 'ng-tooltip-bottom');
this.renderer.addClass(this.tooltip, 'ng-tooltip-top');
this.renderer.setStyle(this.tooltip, 'top', hostPos.top - tooltipPos.height + 'px');
this.renderer.setStyle(this.tooltip, 'left', hostPos.left + 'px');
} else {
this.renderer.setStyle(this.tooltip, 'top', hostPos.bottom + 'px');
this.renderer.setStyle(this.tooltip, 'left', hostPos.left + 'px');
}
}
if (this.placement === 'left') {

View file

@ -1,6 +1,8 @@
import {Injectable} from '@angular/core';
import {Observable} from 'rxjs';
import {TranslateService} from '@ngx-translate/core';
import {VariablesService} from './variables.service';
import {ModalService} from './modal.service';
import {MoneyToIntPipe} from '../pipes/money-to-int.pipe';
@Injectable()
@ -9,9 +11,7 @@ export class BackendService {
backendObject: any;
backendLoaded = false;
constructor(private variablesService: VariablesService, private moneyToIntPipe: MoneyToIntPipe) {
}
constructor(private translate: TranslateService, private variablesService: VariablesService, private modalService: ModalService, private moneyToIntPipe: MoneyToIntPipe) {}
private Debug(type, message) {
switch (type) {
@ -35,11 +35,11 @@ export class BackendService {
switch (error) {
case 'NOT_ENOUGH_MONEY':
error_translate = 'ERROR.NOT_ENOUGH_MONEY';
error_translate = 'ERRORS.NOT_ENOUGH_MONEY';
break;
case 'CORE_BUSY':
if (command !== 'get_all_aliases') {
error_translate = 'INFORMER.CORE_BUSY';
error_translate = 'ERRORS.CORE_BUSY';
}
break;
case 'OVERFLOW':
@ -48,62 +48,62 @@ export class BackendService {
}
break;
case 'INTERNAL_ERROR:daemon is busy':
error_translate = 'INFORMER.DAEMON_BUSY';
error_translate = 'ERRORS.DAEMON_BUSY';
break;
case 'INTERNAL_ERROR:not enough money':
case 'INTERNAL_ERROR:NOT_ENOUGH_MONEY':
if (command === 'cancel_offer') {
// error_translate = $filter('translate')('INFORMER.NO_MONEY_REMOVE_OFFER', {
// 'fee': CONFIG.standart_fee,
// 'currency': CONFIG.currency_symbol
// });
error_translate = this.translate.instant('ERRORS.NO_MONEY_REMOVE_OFFER', {
'fee': '0.01',
'currency': 'ZAN'
});
} else {
error_translate = 'INFORMER.NO_MONEY';
}
break;
case 'INTERNAL_ERROR:not enough outputs to mix':
error_translate = 'MESSAGE.NOT_ENOUGH_OUTPUTS_TO_MIX';
error_translate = 'ERRORS.NOT_ENOUGH_OUTPUTS_TO_MIX';
break;
case 'INTERNAL_ERROR:transaction is too big':
error_translate = 'MESSAGE.TRANSACTION_IS_TO_BIG';
error_translate = 'ERRORS.TRANSACTION_IS_TO_BIG';
break;
case 'INTERNAL_ERROR:Transfer attempt while daemon offline':
error_translate = 'MESSAGE.TRANSFER_ATTEMPT';
error_translate = 'ERRORS.TRANSFER_ATTEMPT';
break;
case 'ACCESS_DENIED':
error_translate = 'INFORMER.ACCESS_DENIED';
error_translate = 'ERRORS.ACCESS_DENIED';
break;
case 'INTERNAL_ERROR:transaction was rejected by daemon':
if (command === 'request_alias_registration') {
error_translate = 'INFORMER.ALIAS_IN_REGISTER';
} else {
error_translate = 'INFORMER.TRANSACTION_ERROR';
}
// if (command === 'request_alias_registration') {
// error_translate = 'INFORMER.ALIAS_IN_REGISTER';
// } else {
error_translate = 'ERRORS.TRANSACTION_ERROR';
// }
break;
case 'INTERNAL_ERROR':
error_translate = 'INFORMER.TRANSACTION_ERROR';
error_translate = 'ERRORS.TRANSACTION_ERROR';
break;
case 'BAD_ARG':
error_translate = 'INFORMER.BAD_ARG';
error_translate = 'ERRORS.BAD_ARG';
break;
case 'WALLET_WRONG_ID':
error_translate = 'INFORMER.WALLET_WRONG_ID';
error_translate = 'ERRORS.WALLET_WRONG_ID';
break;
case 'WRONG_PASSWORD':
case 'WRONG_PASSWORD:invalid password':
params = JSON.parse(params);
if (!params.testEmpty) {
error_translate = 'INFORMER.WRONG_PASSWORD';
error_translate = 'ERRORS.WRONG_PASSWORD';
}
break;
case 'FILE_RESTORED':
if (command === 'open_wallet') {
// error_translate = $filter('translate')('INFORMER.FILE_RESTORED');
error_translate = 'ERRORS.FILE_RESTORED';
}
break;
case 'FILE_NOT_FOUND':
if (command !== 'open_wallet' && command !== 'get_alias_info_by_name' && command !== 'get_alias_info_by_address') {
// error_translate = $filter('translate')('INFORMER.FILE_NOT_FOUND');
error_translate = this.translate.instant('ERRORS.FILE_NOT_FOUND');
params = JSON.parse(params);
if (params.path) {
error_translate += ': ' + params.path;
@ -119,16 +119,16 @@ export class BackendService {
}
break;
case 'ALREADY_EXISTS':
error_translate = 'INFORMER.FILE_EXIST';
error_translate = 'ERRORS.FILE_EXIST';
break;
default:
error_translate = error;
}
if (error.indexOf('FAIL:failed to save file') > -1) {
error_translate = 'INFORMER.FILE_NOT_SAVED';
error_translate = 'ERRORS.FILE_NOT_SAVED';
}
if (error_translate !== '') {
alert(error_translate);
this.modalService.prepareModal('error', error_translate);
}
}
@ -272,7 +272,7 @@ export class BackendService {
}
storeSecureAppData(callback) {
if ( this.variablesService.appPass === '' ) {
if (this.variablesService.appPass === '') {
return callback(false);
}
const wallets = [];
@ -461,6 +461,10 @@ export class BackendService {
this.runCommand('stop_pos_mining', {wallet_id: parseInt(wallet_id, 10)}, callback);
}
openUrlInBrowser(url, callback?) {
this.runCommand('open_url_in_browser', url, callback);
}
}
@ -653,9 +657,7 @@ export class BackendService {
return this.runCommand('print_log', {msg: msg, log_level: log_level});
},
openUrlInBrowser: function (url, callback) {
return this.runCommand('open_url_in_browser', url, callback);
},

View file

@ -0,0 +1,12 @@
import { TestBed } from '@angular/core/testing';
import { ModalService } from './modal.service';
describe('ModalService', () => {
beforeEach(() => TestBed.configureTestingModule({}));
it('should be created', () => {
const service: ModalService = TestBed.get(ModalService);
expect(service).toBeTruthy();
});
});

View file

@ -0,0 +1,52 @@
import {Injectable, Injector, ComponentFactoryResolver, EmbeddedViewRef, ApplicationRef, NgZone} from '@angular/core';
import {TranslateService} from '@ngx-translate/core';
import {ModalContainerComponent} from '../directives/modal-container/modal-container.component';
@Injectable()
export class ModalService {
private components: any[] = [];
constructor(
private componentFactoryResolver: ComponentFactoryResolver,
private appRef: ApplicationRef,
private injector: Injector,
private ngZone: NgZone,
private translate: TranslateService
) {}
prepareModal(type, message) {
const length = this.components.push(
this.componentFactoryResolver.resolveComponentFactory(ModalContainerComponent).create(this.injector)
);
this.components[length - 1].instance['type'] = type;
this.components[length - 1].instance['message'] = this.translate.instant(message);
this.components[length - 1].instance['close'].subscribe(() => {
this.removeModal(length - 1);
});
this.ngZone.run(() => {
this.appendModal(length - 1);
});
}
appendModal(index) {
this.appRef.attachView(this.components[index].hostView);
const domElem = (this.components[index].hostView as EmbeddedViewRef<any>).rootNodes[0] as HTMLElement;
document.body.appendChild(domElem);
}
removeModal(index) {
if (this.components[index]) {
this.appRef.detachView(this.components[index].hostView);
this.components[index].destroy();
this.components.splice(index, 1);
} else {
const last = this.components.length - 1;
this.appRef.detachView(this.components[last].hostView);
this.components[last].destroy();
this.components.splice(last, 1);
}
}
}

View file

@ -82,7 +82,7 @@ export class VariablesService {
}
startCountdown() {
this.idle.restart();
this.idle.start();
}
stopCountdown() {

View file

@ -75,7 +75,7 @@ const routes: Routes = [
},
{
path: '',
redirectTo: 'send',
redirectTo: 'history',
pathMatch: 'full'
}
]

View file

@ -385,7 +385,6 @@ export class AppComponent implements OnInit, OnDestroy {
}
getMoneyEquivalent() {
// todo now start only once, need check daemon state and re-init
this.http.get('https://api.coinmarketcap.com/v2/ticker/2').subscribe(
result => {
if (result.hasOwnProperty('data')) {
@ -393,6 +392,9 @@ export class AppComponent implements OnInit, OnDestroy {
}
},
error => {
setTimeout(() => {
this.getMoneyEquivalent();
}, 60000);
console.warn('Error coinmarketcap', error);
}
);

View file

@ -29,6 +29,7 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { TypingMessageComponent } from './typing-message/typing-message.component';
import { BackendService } from './_helpers/services/backend.service';
import { ModalService } from './_helpers/services/modal.service';
import { MoneyToIntPipe } from './_helpers/pipes/money-to-int.pipe';
import { IntToMoneyPipe } from './_helpers/pipes/int-to-money.pipe';
import { StakingSwitchComponent } from './_helpers/directives/staking-switch/staking-switch.component';
@ -105,10 +106,14 @@ Highcharts.setOptions({
],
providers: [
BackendService,
ModalService,
MoneyToIntPipe,
IntToMoneyPipe,
// {provide: HIGHCHARTS_MODULES, useFactory: () => [ highstock, more, exporting ] }
],
entryComponents: [
ModalContainerComponent
],
bootstrap: [AppComponent]
})
export class AppModule { }

View file

@ -10,60 +10,71 @@
margin: -3rem -3rem 0 -3rem;
overflow-x: auto;
.contract {
position: relative;
display: flex;
align-items: center;
table {
.icon {
flex-shrink: 0;
tbody {
&.new, &.alert {
position: absolute;
top: 0;
}
tr {
cursor: pointer;
outline: none !important;
&.new {
left: -2.3rem;
mask: url(../../assets/icons/new.svg) no-repeat center;
width: 1.7rem;
height: 1.7rem;
}
.contract {
position: relative;
display: flex;
align-items: center;
&.alert {
top: 0.2rem;
left: -2.1rem;
mask: url(../../assets/icons/alert.svg) no-repeat center;
width: 1.2rem;
height: 1.2rem;
}
.icon {
flex-shrink: 0;
&.purchase, &.sell {
margin-right: 1rem;
width: 1.5rem;
height: 1.5rem;
}
&.new, &.alert {
position: absolute;
top: 0;
}
&.purchase {
mask: url(../../assets/icons/purchase.svg) no-repeat center;
}
&.new {
left: -2.3rem;
mask: url(../../assets/icons/new.svg) no-repeat center;
width: 1.7rem;
height: 1.7rem;
}
&.sell {
mask: url(../../assets/icons/sell.svg) no-repeat center;
&.alert {
top: 0.2rem;
left: -2.1rem;
mask: url(../../assets/icons/alert.svg) no-repeat center;
width: 1.2rem;
height: 1.2rem;
}
&.purchase, &.sell {
margin-right: 1rem;
width: 1.5rem;
height: 1.5rem;
}
&.purchase {
mask: url(../../assets/icons/purchase.svg) no-repeat center;
}
&.sell {
mask: url(../../assets/icons/sell.svg) no-repeat center;
}
}
span {
text-overflow: ellipsis;
overflow: hidden;
max-width: 20vw;
}
}
.status, .comment {
text-overflow: ellipsis;
overflow: hidden;
max-width: 20vw;
}
}
}
span {
text-overflow: ellipsis;
overflow: hidden;
max-width: 20vw;
}
}
.status, .comment {
text-overflow: ellipsis;
overflow: hidden;
max-width: 20vw;
}
}

View file

@ -16,7 +16,8 @@ export class ContractsComponent implements OnInit, OnDestroy {
private route: ActivatedRoute,
private router: Router,
private variablesService: VariablesService
) {}
) {
}
ngOnInit() {
this.parentRouting = this.route.parent.params.subscribe(params => {

View file

@ -2,7 +2,7 @@
<div class="head">
<div class="breadcrumbs">
<span>{{ 'BREADCRUMBS.ADD_WALLET' | translate }}</span>
<span [routerLink]="['/main']">{{ 'BREADCRUMBS.ADD_WALLET' | translate }}</span>
<span>{{ 'BREADCRUMBS.CREATE_WALLET' | translate }}</span>
</div>
<a class="back-btn" [routerLink]="['/main']">

View file

@ -2,8 +2,10 @@ import {Component, NgZone, OnInit} from '@angular/core';
import {FormGroup, FormControl, Validators} from '@angular/forms';
import {BackendService} from '../_helpers/services/backend.service';
import {VariablesService} from '../_helpers/services/variables.service';
import {ModalService} from '../_helpers/services/modal.service';
import {Router} from '@angular/router';
import {Wallet} from '../_helpers/models/wallet.model';
import {TranslateService} from '@ngx-translate/core';
@Component({
selector: 'app-create-wallet',
@ -37,7 +39,9 @@ export class CreateWalletComponent implements OnInit {
private router: Router,
private backend: BackendService,
private variablesService: VariablesService,
private ngZone: NgZone
private modalService: ModalService,
private ngZone: NgZone,
private translate: TranslateService
) {
}
@ -50,7 +54,7 @@ export class CreateWalletComponent implements OnInit {
saveWallet() {
if (this.createForm.valid) {
this.backend.saveFileDialog('Save the wallet file.', '*', this.variablesService.settings.default_path, (file_status, file_data) => {
this.backend.saveFileDialog(this.translate.instant('CREATE_WALLET.TITLE_SAVE'), '*', this.variablesService.settings.default_path, (file_status, file_data) => {
if (file_status) {
this.variablesService.settings.default_path = file_data.path.substr(0, file_data.path.lastIndexOf('/'));
this.backend.generateWallet(file_data.path, this.createForm.get('password').value, (generate_status, generate_data, errorCode) => {
@ -72,9 +76,9 @@ export class CreateWalletComponent implements OnInit {
});
} else {
if (errorCode && errorCode === 'ALREADY_EXISTS') {
alert('You cannot record a file on top of another file');
this.modalService.prepareModal('error', 'CREATE_WALLET.ERROR_CANNOT_SAVE_TOP');
} else {
alert('You cannot save a safe file to the system partition');
this.modalService.prepareModal('error', 'CREATE_WALLET.ERROR_CANNOT_SAVE_SYSTEM');
}
}
});

View file

@ -13,15 +13,19 @@
<tr *ngFor="let item of variablesService.currentWallet.history">
<td>
<div class="status" [class.send]="!item.is_income" [class.received]="item.is_income">
<div class="confirmation" tooltip="{{ 'HISTORY.STATUS_TOOLTIP' | translate : {'current': getHeight(item)/10, 'total': 10} }}" placement="bottom" tooltipClass="history-tooltip" delay="500">
<div class="fill" [style.height]="getHeight(item) + '%'"></div>
</div>
<ng-container *ngIf="variablesService.height_app - item.height <= 10 || item.height === 0 || (item.is_mining && item.height === 0)">
<div class="confirmation" tooltip="{{ 'HISTORY.STATUS_TOOLTIP' | translate : {'current': getHeight(item)/10, 'total': 10} }}" placement="bottom" tooltipClass="history-tooltip" delay="500">
<div class="fill" [style.height]="getHeight(item) + '%'"></div>
</div>
</ng-container>
<i class="icon"></i>
<span>{{ (item.is_income ? 'HISTORY.RECEIVED' : 'HISTORY.SEND') | translate }}</span>
</div>
</td>
<td>{{item.timestamp * 1000 | date : 'dd-MM-yyyy HH:mm'}}</td>
<td>{{item.sortAmount | intToMoney}} {{variablesService.defaultCurrency}}</td>
<td>
<span *ngIf="item.sortAmount">{{item.sortAmount | intToMoney}} {{variablesService.defaultCurrency}}</span>
</td>
<td>
<span *ngIf="item.sortFee">{{item.sortFee | intToMoney}} {{variablesService.defaultCurrency}}</span>
</td>

View file

@ -1,6 +1,4 @@
import {Component, OnInit, OnDestroy} from '@angular/core';
import {ActivatedRoute} from '@angular/router';
import {BackendService} from '../_helpers/services/backend.service';
import {VariablesService} from '../_helpers/services/variables.service';
@Component({
@ -9,19 +7,11 @@ import {VariablesService} from '../_helpers/services/variables.service';
styleUrls: ['./history.component.scss']
})
export class HistoryComponent implements OnInit, OnDestroy {
parentRouting;
constructor(
private route: ActivatedRoute,
private backend: BackendService,
private variablesService: VariablesService
) {
constructor(private variablesService: VariablesService) {
}
ngOnInit() {
this.parentRouting = this.route.parent.params.subscribe(() => {
console.log(this.variablesService.currentWallet.history);
});
}
getHeight(item) {
@ -37,7 +27,6 @@ export class HistoryComponent implements OnInit, OnDestroy {
}
ngOnDestroy() {
this.parentRouting.unsubscribe();
}
}

View file

@ -14,9 +14,9 @@
max-width: 40rem;
.logo {
background: url("../../assets/images/logo.png") no-repeat center top;
background: url(../../assets/icons/logo.svg) no-repeat center;
width: 100%;
height: 14rem;
height: 20rem;
}
.form-login {

View file

@ -1,8 +1,9 @@
import {Component, NgZone, OnInit} from '@angular/core';
import {Component, NgZone, OnInit, OnDestroy} from '@angular/core';
import {FormGroup, FormControl, Validators} from '@angular/forms';
import {ActivatedRoute, Router} from '@angular/router';
import {BackendService} from '../_helpers/services/backend.service';
import {VariablesService} from '../_helpers/services/variables.service';
import {ModalService} from '../_helpers/services/modal.service';
import {Wallet} from '../_helpers/models/wallet.model';
@Component({
@ -10,7 +11,9 @@ import {Wallet} from '../_helpers/models/wallet.model';
templateUrl: './login.component.html',
styleUrls: ['./login.component.scss']
})
export class LoginComponent implements OnInit {
export class LoginComponent implements OnInit, OnDestroy {
queryRouting;
regForm = new FormGroup({
password: new FormControl('', Validators.required),
@ -30,12 +33,13 @@ export class LoginComponent implements OnInit {
private router: Router,
private backend: BackendService,
private variablesService: VariablesService,
private modalService: ModalService,
private ngZone: NgZone
) {
}
ngOnInit() {
this.route.queryParams.subscribe(params => {
this.queryRouting = this.route.queryParams.subscribe(params => {
if (params.type) {
this.type = params.type;
}
@ -51,7 +55,6 @@ export class LoginComponent implements OnInit {
this.router.navigate(['/']);
});
} else {
// TODO error sign in
console.log(data['error_code']);
}
});
@ -62,10 +65,7 @@ export class LoginComponent implements OnInit {
if (this.authForm.valid) {
const appPass = this.authForm.get('password').value;
this.backend.getSecureAppData({pass: appPass}, (status, data) => {
if (data.error_code && data.error_code === 'WRONG_PASSWORD') {
// TODO error log in informer.error('MESSAGE.INCORRECT_PASSWORD');
console.log('WRONG_PASSWORD');
} else {
if (!data.error_code) {
this.variablesService.startCountdown();
this.variablesService.appPass = appPass;
if (this.variablesService.wallets.length) {
@ -139,4 +139,10 @@ export class LoginComponent implements OnInit {
});
}
}
ngOnDestroy() {
this.queryRouting.unsubscribe();
}
}

View file

@ -6,7 +6,7 @@
<button type="button" class="blue-button" (click)="openWallet()">{{ 'MAIN.BUTTON_OPEN_WALLET' | translate }}</button>
<button type="button" class="blue-button" [routerLink]="['/restore']">{{ 'MAIN.BUTTON_RESTORE_BACKUP' | translate }}</button>
</div>
<div class="add-wallet-help">
<div class="add-wallet-help" (click)="openInBrowser()">
<i class="icon"></i><span>{{ 'MAIN.HELP' | translate }}</span>
</div>
</div>

View file

@ -29,6 +29,7 @@
.add-wallet-help {
display: flex;
cursor: pointer;
font-size: 1.3rem;
line-height: 1.4rem;

View file

@ -2,6 +2,7 @@ import {Component, NgZone, OnInit} from '@angular/core';
import {BackendService} from '../_helpers/services/backend.service';
import {VariablesService} from '../_helpers/services/variables.service';
import {Router} from '@angular/router';
import {TranslateService} from '@ngx-translate/core';
@Component({
selector: 'app-main',
@ -14,13 +15,14 @@ export class MainComponent implements OnInit {
private router: Router,
private backend: BackendService,
private variablesService: VariablesService,
private ngZone: NgZone
private ngZone: NgZone,
private translate: TranslateService
) {}
ngOnInit() {}
openWallet() {
this.backend.openFileDialog('Open the wallet file.', '*', this.variablesService.settings.default_path, (file_status, file_data) => {
this.backend.openFileDialog(this.translate.instant('MAIN.CHOOSE_PATH'), '*', this.variablesService.settings.default_path, (file_status, file_data) => {
if (file_status) {
this.variablesService.settings.default_path = file_data.path.substr(0, file_data.path.lastIndexOf('/'));
this.ngZone.run(() => {
@ -32,4 +34,8 @@ export class MainComponent implements OnInit {
});
}
openInBrowser() {
this.backend.openUrlInBrowser('zano.org');
}
}

View file

@ -2,7 +2,7 @@
<div class="head">
<div class="breadcrumbs">
<span>{{ 'BREADCRUMBS.ADD_WALLET' | translate }}</span>
<span [routerLink]="['/main']">{{ 'BREADCRUMBS.ADD_WALLET' | translate }}</span>
<span>{{ 'BREADCRUMBS.OPEN_WALLET' | translate }}</span>
</div>
<a class="back-btn" [routerLink]="['/main']">

View file

@ -1,17 +1,20 @@
import {Component, NgZone, OnInit} from '@angular/core';
import {Component, NgZone, OnDestroy, OnInit} from '@angular/core';
import {FormGroup, FormControl, Validators} from '@angular/forms';
import {BackendService} from '../_helpers/services/backend.service';
import {VariablesService} from '../_helpers/services/variables.service';
import {ModalService} from '../_helpers/services/modal.service';
import {ActivatedRoute, Router} from '@angular/router';
import {Wallet} from '../_helpers/models/wallet.model';
import {TranslateService} from '@ngx-translate/core';
@Component({
selector: 'app-open-wallet',
templateUrl: './open-wallet.component.html',
styleUrls: ['./open-wallet.component.scss']
})
export class OpenWalletComponent implements OnInit {
export class OpenWalletComponent implements OnInit, OnDestroy {
queryRouting;
filePath: string;
openForm = new FormGroup({
@ -31,12 +34,14 @@ export class OpenWalletComponent implements OnInit {
private router: Router,
private backend: BackendService,
private variablesService: VariablesService,
private ngZone: NgZone
private modalService: ModalService,
private ngZone: NgZone,
private translate: TranslateService
) {
}
ngOnInit() {
this.route.queryParams.subscribe(params => {
this.queryRouting = this.route.queryParams.subscribe(params => {
if (params.path) {
this.filePath = params.path;
let filename = '';
@ -57,11 +62,11 @@ export class OpenWalletComponent implements OnInit {
if (this.openForm.valid) {
this.backend.openWallet(this.filePath, this.openForm.get('password').value, false, (open_status, open_data, open_error) => {
if (open_error && open_error === 'FILE_NOT_FOUND') {
// var error_translate = $filter('translate')('INFORMER.SAFE_FILE_NOT_FOUND1');
let error_translate = this.translate.instant('OPEN_WALLET.SAFE_FILE_NOT_FOUND1');
// error_translate += ':<br>' + $scope.safe.path;
// error_translate += $filter('translate')('INFORMER.SAFE_FILE_NOT_FOUND2');
// informer.fileNotFound(error_translate);
alert('FILE_NOT_FOUND');
error_translate += ':<br>' + this.filePath;
error_translate += this.translate.instant('OPEN_WALLET.SAFE_FILE_NOT_FOUND2');
this.modalService.prepareModal('error', error_translate);
} else {
if (open_status || open_error === 'FILE_RESTORED') {
@ -73,9 +78,8 @@ export class OpenWalletComponent implements OnInit {
});
if (exists) {
alert('SAFES.WITH_ADDRESS_ALREADY_OPEN');
this.modalService.prepareModal('error', 'OPEN_WALLET.WITH_ADDRESS_ALREADY_OPEN');
this.backend.closeWallet(open_data.wallet_id, (close_status, close_data) => {
console.log(close_status, close_data);
this.ngZone.run(() => {
this.router.navigate(['/']);
});
@ -122,4 +126,8 @@ export class OpenWalletComponent implements OnInit {
}
}
ngOnDestroy() {
this.queryRouting.unsubscribe();
}
}

View file

@ -1,6 +1,6 @@
<div class="head">
<div class="breadcrumbs">
<span>{{ 'BREADCRUMBS.CONTRACTS' | translate }}</span>
<span [routerLink]="'/wallet/' + currentWalletId + '/contracts'">{{ 'BREADCRUMBS.CONTRACTS' | translate }}</span>
<span *ngIf="newPurchase">{{ 'BREADCRUMBS.NEW_PURCHASE' | translate }}</span>
<span *ngIf="!newPurchase">{{ 'BREADCRUMBS.OLD_PURCHASE' | translate }}</span>
</div>
@ -78,7 +78,7 @@
<div class="input-block">
<label for="purchase-comment">{{ 'PURCHASE.COMMENT' | translate }}</label>
<input type="text" id="purchase-comment" formControlName="comment" (contextmenu)="variablesService.onContextMenu($event)">
<input type="text" id="purchase-comment" formControlName="comment" [readonly]="!newPurchase" (contextmenu)="variablesService.onContextMenu($event)">
</div>
<button type="button" class="purchase-select" (click)="toggleOptions()">
@ -90,6 +90,14 @@
<label for="purchase-fee">{{ 'PURCHASE.FEE' | translate }}</label>
<input type="text" id="purchase-fee" formControlName="fee" readonly>
</div>
<div class="input-block" *ngIf="newPurchase">
<label for="purchase-time">{{ 'PURCHASE.WAITING_TIME' | translate }}</label>
<select id="purchase-time" formControlName="time">
<option *ngFor="let title of [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24]" [value]="title">
{{title}}
</option>
</select>
</div>
<div class="input-block">
<label for="purchase-payment">{{ 'PURCHASE.PAYMENT' | translate }}</label>
<input type="text" id="purchase-payment" formControlName="payment" [readonly]="!newPurchase" (contextmenu)="variablesService.onContextMenu($event)">
@ -105,7 +113,7 @@
</ng-container>
<ng-container *ngIf="currentContract.is_a">
<span *ngIf="currentContract.state == 1">{{ 'DEALS.CUSTOMER_WAITING_ANSWER' | translate }}</span>
<span *ngIf="currentContract.state == 1">{{ 'Waiting for seller respond to contract proposal' | translate }}</span>
<!--<span *ngIf="currentContract.state == 1" ng-bind="'(' + (currentContract.expiration_time | buyingTime : 0) + ')'"></span>-->
<span *ngIf="currentContract.state == 110">{{ 'The seller ignored your contract proposal' | translate }}</span>
@ -167,8 +175,9 @@
</ng-container>
<ng-container *ngIf="currentContract.state == 201 || currentContract.state == 601">
<span *ngIf="(variablesService.height_app - currentContract.height) < 10">{{variablesService.height_app - currentContract.height}}/10</span>
<span *ngIf="historyBlock && historyBlock.sortAmount">{{(historyBlock.is_income ? '+' : '') + (historyBlock.sortAmount | intToMoney)}}</span>
<span *ngIf="currentContract.height === 0">0/10</span>
<span *ngIf="currentContract.height !== 0 && (variablesService.height_app - currentContract.height) < 10">{{variablesService.height_app - currentContract.height}}/10</span>
<span *ngIf="historyBlock && historyBlock.sortAmount">{{(historyBlock.is_income ? '+' : '') + (historyBlock.sortAmount | intToMoney)}} {{variablesService.defaultCurrency}}</span>
</ng-container>
</div>
@ -204,6 +213,17 @@
</div>
<div style="display: flex; justify-content: center;" *ngIf="!newPurchase && currentContract.is_a && (currentContract.state == 201 || currentContract.state == 2 || currentContract.state == 120 || currentContract.state == 130)">
<div class="input-block">
<label for="purchase-timeCancel">{{ 'PURCHASE.WAITING_TIME' | translate }}</label>
<select id="purchase-timeCancel" formControlName="timeCancel">
<option *ngFor="let title of [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24]" [value]="title">
{{title}}
</option>
</select>
</div>
</div>
</form>
<div class="progress-bar-container">

View file

@ -3,8 +3,10 @@ import {ActivatedRoute} from '@angular/router';
import {FormControl, FormGroup, Validators} from '@angular/forms';
import {BackendService} from '../_helpers/services/backend.service';
import {VariablesService} from '../_helpers/services/variables.service';
import {ModalService} from '../_helpers/services/modal.service';
import {Location} from '@angular/common';
import {IntToMoneyPipe} from '../_helpers/pipes/int-to-money.pipe';
import {TranslateService} from '@ngx-translate/core';
@Component({
selector: 'app-purchase',
@ -15,6 +17,7 @@ export class PurchaseComponent implements OnInit, OnDestroy {
currentWalletId;
newPurchase = false;
parentRouting;
subRouting;
historyBlock;
purchaseForm = new FormGroup({
@ -26,19 +29,24 @@ export class PurchaseComponent implements OnInit, OnDestroy {
sameAmount: new FormControl(false),
comment: new FormControl(''),
fee: new FormControl('0.01'),
time: new FormControl({value: '12', disabled: false}),
timeCancel: new FormControl('12'),
payment: new FormControl('')
});
additionalOptions = false;
currentContract = null;
heightAppEvent;
constructor(
private route: ActivatedRoute,
private backend: BackendService,
private variablesService: VariablesService,
private modalService: ModalService,
private ngZone: NgZone,
private location: Location,
private intToMoneyPipe: IntToMoneyPipe
private intToMoneyPipe: IntToMoneyPipe,
private translate: TranslateService
) {
}
@ -54,7 +62,7 @@ export class PurchaseComponent implements OnInit, OnDestroy {
this.parentRouting = this.route.parent.params.subscribe(params => {
this.currentWalletId = params['id'];
});
this.route.params.subscribe(params => {
this.subRouting = this.route.params.subscribe(params => {
if (params.hasOwnProperty('id')) {
this.currentContract = this.variablesService.currentWallet.getContract(params['id']);
this.purchaseForm.setValue({
@ -66,23 +74,12 @@ export class PurchaseComponent implements OnInit, OnDestroy {
sameAmount: false,
comment: this.currentContract.private_detailes.c,
fee: '0.01',
time: '12',
timeCancel: '12',
payment: this.currentContract.payment_id
});
this.newPurchase = false;
// todo original code watch height_v
if (this.currentContract.state === 201 && this.currentContract.height !== 0 && (this.variablesService.height_app - this.currentContract.height) >= 10) {
this.currentContract.state = 2;
this.currentContract.is_new = true;
this.variablesService.currentWallet.recountNewContracts();
} else if (this.currentContract.state === 601 && this.currentContract.height !== 0 && (this.variablesService.height_app - this.currentContract.height) >= 10) {
this.currentContract.state = 6;
this.currentContract.is_new = true;
this.variablesService.currentWallet.recountNewContracts();
}
if (this.currentContract.is_new) {
if (this.currentContract.is_a && this.currentContract.state === 2) {
this.currentContract.state = 120;
@ -109,19 +106,27 @@ export class PurchaseComponent implements OnInit, OnDestroy {
}
this.currentContract.is_new = false;
// todo need remove timeout
setTimeout(() => {
this.variablesService.currentWallet.recountNewContracts();
}, 0);
this.checkAndChangeHistory();
}
this.checkAndChangeHistory();
} else {
this.newPurchase = true;
}
});
this.heightAppEvent = this.variablesService.getHeightAppEvent.subscribe((newHeight: number) => {
if (this.currentContract && this.currentContract.state === 201 && this.currentContract.height !== 0 && (newHeight - this.currentContract.height) >= 10) {
this.currentContract.state = 2;
this.currentContract.is_new = true;
this.variablesService.currentWallet.recountNewContracts();
} else if (this.currentContract && this.currentContract.state === 601 && this.currentContract.height !== 0 && (newHeight - this.currentContract.height) >= 10) {
this.currentContract.state = 6;
this.currentContract.is_new = true;
this.variablesService.currentWallet.recountNewContracts();
}
});
}
toggleOptions() {
@ -129,11 +134,17 @@ export class PurchaseComponent implements OnInit, OnDestroy {
}
getProgressBarWidth() {
if (this.newPurchase) {
return '9rem';
} else {
return '50%';
let progress = '9rem';
if (!this.newPurchase) {
if (this.currentContract) {
if ([110, 3, 4, 6, 140].indexOf(this.currentContract.state) !== -1) {
progress = '100%';
} else {
progress = '50%';
}
}
}
return progress;
}
sameAmountChange() {
@ -172,10 +183,12 @@ export class PurchaseComponent implements OnInit, OnDestroy {
this.purchaseForm.get('amount').value,
this.purchaseForm.get('yourDeposit').value,
this.purchaseForm.get('sellerDeposit').value,
12,
this.purchaseForm.get('time').value,
this.purchaseForm.get('payment').value,
() => {
this.back();
(create_status) => {
if (create_status) {
this.back();
}
});
}
}
@ -187,7 +200,7 @@ export class PurchaseComponent implements OnInit, OnDestroy {
acceptState() {
this.backend.acceptProposal(this.currentWalletId, this.currentContract.contract_id, (accept_status) => {
if (accept_status) {
alert('You have accepted the contract proposal. Please wait for the pledges to be made');
this.modalService.prepareModal('info', 'PURCHASE.ACCEPT_STATE_WAIT_BIG');
this.back();
}
});
@ -217,7 +230,7 @@ export class PurchaseComponent implements OnInit, OnDestroy {
this.currentContract.time = this.currentContract.expiration_time;
this.variablesService.currentWallet.recountNewContracts();
alert('You have ignored the contract proposal');
this.modalService.prepareModal('info', 'PURCHASE.IGNORED_ACCEPT');
this.back();
}
@ -225,7 +238,7 @@ export class PurchaseComponent implements OnInit, OnDestroy {
productNotGot() {
this.backend.releaseProposal(this.currentWalletId, this.currentContract.contract_id, 'REL_B', (release_status) => {
if (release_status) {
alert('The pledges have been nullified.');
this.modalService.prepareModal('info', 'PURCHASE.BURN_PROPOSAL');
this.back();
}
});
@ -234,16 +247,16 @@ export class PurchaseComponent implements OnInit, OnDestroy {
dealsDetailsFinish() {
this.backend.releaseProposal(this.currentWalletId, this.currentContract.contract_id, 'REL_N', (release_status) => {
if (release_status) {
alert('The contract is complete. The payment has been sent.');
this.modalService.prepareModal('success', 'PURCHASE.SUCCESS_FINISH_PROPOSAL');
this.back();
}
});
}
dealsDetailsCancel() {
this.backend.requestCancelContract(this.currentWalletId, this.currentContract.contract_id, 12, (cancel_status) => {
this.backend.requestCancelContract(this.currentWalletId, this.currentContract.contract_id, this.purchaseForm.get('timeCancel').value, (cancel_status) => {
if (cancel_status) {
alert('Proposal to cancel contract sent to seller');
this.modalService.prepareModal('info', 'PURCHASE.SEND_CANCEL_PROPOSAL');
this.back();
}
});
@ -273,14 +286,14 @@ export class PurchaseComponent implements OnInit, OnDestroy {
this.currentContract.time = this.currentContract.cancel_expiration_time;
this.variablesService.currentWallet.recountNewContracts();
alert('You have ignored the proposal to cancel the contract');
this.modalService.prepareModal('info', 'PURCHASE.IGNORED_CANCEL');
this.back();
}
dealsDetailsSellerCancel() {
this.backend.acceptCancelContract(this.currentWalletId, this.currentContract.contract_id, (accept_status) => {
if (accept_status) {
alert('The contract is being cancelled. Please wait for the pledge to be returned');
this.modalService.prepareModal('info', 'PURCHASE.DEALS_CANCELED_WAIT');
this.back();
}
});
@ -288,6 +301,8 @@ export class PurchaseComponent implements OnInit, OnDestroy {
ngOnDestroy() {
this.parentRouting.unsubscribe();
this.subRouting.unsubscribe();
this.heightAppEvent.unsubscribe();
}
}

View file

@ -1,7 +1,7 @@
<div class="content">
<div class="head">
<div class="breadcrumbs">
<span>{{ 'BREADCRUMBS.ADD_WALLET' | translate }}</span>
<span [routerLink]="['/main']">{{ 'BREADCRUMBS.ADD_WALLET' | translate }}</span>
<span>{{ 'BREADCRUMBS.RESTORE_WALLET' | translate }}</span>
</div>
<a class="back-btn" [routerLink]="['/main']">

View file

@ -3,7 +3,9 @@ import {FormGroup, FormControl, Validators} from '@angular/forms';
import {Router} from '@angular/router';
import {BackendService} from '../_helpers/services/backend.service';
import {VariablesService} from '../_helpers/services/variables.service';
import {ModalService} from '../_helpers/services/modal.service';
import {Wallet} from '../_helpers/models/wallet.model';
import {TranslateService} from '@ngx-translate/core';
@Component({
selector: 'app-restore-wallet',
@ -38,7 +40,9 @@ export class RestoreWalletComponent implements OnInit {
private router: Router,
private backend: BackendService,
private variablesService: VariablesService,
private ngZone: NgZone
private modalService: ModalService,
private ngZone: NgZone,
private translate: TranslateService
) {
}
@ -59,7 +63,7 @@ export class RestoreWalletComponent implements OnInit {
this.restoreForm.get('key').setErrors({key_not_valid: true});
});
} else {
this.backend.saveFileDialog('Save the wallet file.', '*', this.variablesService.settings.default_path, (save_status, save_data) => {
this.backend.saveFileDialog(this.translate.instant('RESTORE_WALLET.CHOOSE_PATH'), '*', this.variablesService.settings.default_path, (save_status, save_data) => {
if (save_status) {
this.variablesService.settings.default_path = save_data.path.substr(0, save_data.path.lastIndexOf('/'));
this.backend.restoreWallet(save_data.path, this.restoreForm.get('password').value, this.restoreForm.get('key').value, (restore_status, restore_data) => {
@ -90,7 +94,7 @@ export class RestoreWalletComponent implements OnInit {
this.walletSaved = true;
});
} else {
alert('SAFES.NOT_CORRECT_FILE_OR_PASSWORD');
this.modalService.prepareModal('error', 'RESTORE_WALLET.NOT_CORRECT_FILE_OR_PASSWORD');
}
});
}

View file

@ -1,7 +1,7 @@
<div class="content">
<div class="head">
<div class="breadcrumbs">
<span>{{ 'BREADCRUMBS.ADD_WALLET' | translate }}</span>
<span [routerLink]="['/main']">{{ 'BREADCRUMBS.ADD_WALLET' | translate }}</span>
<span>{{ 'BREADCRUMBS.SAVE_PHRASE' | translate }}</span>
</div>
<a class="back-btn" [routerLink]="['/main']">

View file

@ -1,4 +1,4 @@
import {Component, NgZone, OnInit} from '@angular/core';
import {Component, NgZone, OnDestroy, OnInit} from '@angular/core';
import {BackendService} from '../_helpers/services/backend.service';
import {ActivatedRoute, Router} from '@angular/router';
import {VariablesService} from '../_helpers/services/variables.service';
@ -8,8 +8,9 @@ import {VariablesService} from '../_helpers/services/variables.service';
templateUrl: './seed-phrase.component.html',
styleUrls: ['./seed-phrase.component.scss']
})
export class SeedPhraseComponent implements OnInit {
export class SeedPhraseComponent implements OnInit, OnDestroy {
queryRouting;
seedPhrase = '';
wallet_id: number;
@ -22,7 +23,7 @@ export class SeedPhraseComponent implements OnInit {
) {}
ngOnInit() {
this.route.queryParams.subscribe(params => {
this.queryRouting = this.route.queryParams.subscribe(params => {
if (params.wallet_id) {
this.wallet_id = params.wallet_id;
this.backend.getSmartSafeInfo(params.wallet_id, (status, data) => {
@ -56,9 +57,6 @@ export class SeedPhraseComponent implements OnInit {
} else {
console.log(run_data['error_code']);
}
// $rootScope.reloadCounters();
// $rootScope.$broadcast('NEED_REFRESH_HISTORY');
// $rootScope.saveSecureData();
});
} else {
this.variablesService.opening_wallet = null;
@ -71,4 +69,8 @@ export class SeedPhraseComponent implements OnInit {
}
}
ngOnDestroy() {
this.queryRouting.unsubscribe();
}
}

View file

@ -3,6 +3,7 @@ import {FormGroup, FormControl, Validators} from '@angular/forms';
import {ActivatedRoute} from '@angular/router';
import {BackendService} from '../_helpers/services/backend.service';
import {VariablesService} from '../_helpers/services/variables.service';
import {ModalService} from '../_helpers/services/modal.service';
@Component({
selector: 'app-send',
@ -26,6 +27,7 @@ export class SendComponent implements OnInit, OnDestroy {
private route: ActivatedRoute,
private backend: BackendService,
private variablesService: VariablesService,
private modalService: ModalService,
private ngZone: NgZone
) {}
@ -65,7 +67,7 @@ export class SendComponent implements OnInit, OnDestroy {
this.sendForm.get('comment').value,
(send_status, send_data) => {
if (send_status) {
alert('SEND_MONEY.SUCCESS_SENT');
this.modalService.prepareModal('success', 'SEND.SUCCESS_SENT');
this.sendForm.reset({address: '', amount: null, comment: '', mixin: 0, fee: '0.01'});
}
});

View file

@ -3,7 +3,7 @@
<h3>{{ 'SIDEBAR.TITLE' | translate }}</h3><button [routerLink]="['main']">{{ 'SIDEBAR.ADD_NEW' | translate }}</button>
</div>
<div class="sidebar-accounts-list scrolled-content">
<div class="sidebar-account" *ngFor="let wallet of variablesService.wallets" [class.active]="wallet?.wallet_id === walletActive" [routerLink]="['/wallet/' + wallet.wallet_id + '/' + walletActiveSubDirectory]">
<div class="sidebar-account" *ngFor="let wallet of variablesService.wallets" [class.active]="wallet?.wallet_id === walletActive" [routerLink]="['/wallet/' + wallet.wallet_id + '/history']">
<div class="sidebar-account-row account-title-balance">
<span class="title">{{wallet.name}}</span>
<span class="balance">{{wallet.unlocked_balance | intToMoney}} {{variablesService.defaultCurrency}}</span>
@ -21,7 +21,7 @@
<span class="indicator">{{wallet.new_contracts}}</span>
</div>
<div class="sidebar-account-row account-synchronization" *ngIf="!wallet.loaded && variablesService.daemon_state === 2">
<span class="status">{{ 'SIDEBAR.SYNCHRONIZATION.SYNCING' | translate }}</span>
<span class="status">{{ 'SIDEBAR.ACCOUNT.SYNCING' | translate }}</span>
<div class="progress-bar-container">
<div class="progress-bar">
<div class="fill" [style.width]="wallet.progress + '%'"></div>

View file

@ -8,7 +8,6 @@ import {VariablesService} from '../_helpers/services/variables.service';
styleUrls: ['./sidebar.component.scss']
})
export class SidebarComponent implements OnInit, OnDestroy {
walletActiveSubDirectory = '';
walletSubRouting;
walletActive: number;
@ -26,9 +25,6 @@ export class SidebarComponent implements OnInit, OnDestroy {
if (localPathArr.length >= 3) {
this.walletActive = parseInt(localPathArr[2], 10);
}
if (localPathArr.length >= 4) {
this.walletActiveSubDirectory = localPathArr[3];
}
} else if (this.router.url.indexOf('/details') !== -1) {
this.walletActive = this.variablesService.currentWallet.wallet_id;
} else {
@ -42,12 +38,6 @@ export class SidebarComponent implements OnInit, OnDestroy {
if (localPathArr.length >= 3) {
this.walletActive = parseInt(localPathArr[2], 10);
}
if (localPathArr.length >= 4) {
this.walletActiveSubDirectory = localPathArr[3];
if (this.walletActiveSubDirectory === 'purchase') {
this.walletActiveSubDirectory = 'contracts';
}
}
} else if (event.url.indexOf('/details') !== -1) {
this.walletActive = this.variablesService.currentWallet.wallet_id;
} else {

View file

@ -1,7 +1,7 @@
<div class="content">
<div class="head">
<div class="breadcrumbs">
<span>{{variablesService.currentWallet.name}}</span>
<span (click)="back()">{{variablesService.currentWallet.name}}</span>
<span>{{ 'BREADCRUMBS.WALLET_DETAILS' | translate }}</span>
</div>
<button type="button" class="back-btn" (click)="back()">

View file

@ -1,7 +1,7 @@
<div class="header">
<div>
<h3>{{variablesService.currentWallet.name}}</h3>
<button>
<button (click)="openInBrowser()">
<i class="icon account"></i>
<span>{{ 'WALLET.REGISTER_ALIAS' | translate }}</span>
</button>

View file

@ -12,12 +12,19 @@ export class WalletComponent implements OnInit, OnDestroy {
subRouting;
walletID;
tabs = [
{
title: 'WALLET.TABS.HISTORY',
icon: 'history',
link: '/history',
indicator: false,
active: true
},
{
title: 'WALLET.TABS.SEND',
icon: 'send',
link: '/send',
indicator: false,
active: true
active: false
},
{
title: 'WALLET.TABS.RECEIVE',
@ -26,13 +33,6 @@ export class WalletComponent implements OnInit, OnDestroy {
indicator: false,
active: false
},
{
title: 'WALLET.TABS.HISTORY',
icon: 'history',
link: '/history',
indicator: false,
active: false
},
{
title: 'WALLET.TABS.CONTRACTS',
icon: 'contracts',
@ -40,13 +40,13 @@ export class WalletComponent implements OnInit, OnDestroy {
indicator: 1,
active: false
},
{
/*{
title: 'WALLET.TABS.MESSAGES',
icon: 'messages',
link: '/messages',
indicator: 32,
active: false
},
},*/
{
title: 'WALLET.TABS.STAKING',
icon: 'staking',
@ -90,20 +90,9 @@ export class WalletComponent implements OnInit, OnDestroy {
this.backend.setClipboard(this.variablesService.currentWallet.address);
}
/*closeWallet() {
this.backend.closeWallet(this.walletID, () => {
for (let i = this.variablesService.wallets.length - 1; i >= 0; i--) {
if (this.variablesService.wallets[i].wallet_id === this.walletID) {
this.variablesService.wallets.splice(i, 1);
}
}
this.backend.storeSecureAppData(() => {
this.ngZone.run(() => {
this.router.navigate(['/']);
});
});
});
}*/
openInBrowser() {
this.backend.openUrlInBrowser('zano.org');
}
ngOnDestroy() {
this.subRouting.unsubscribe();

View file

@ -3,7 +3,8 @@
"SETUP_MASTER_PASS": "Setup master password",
"SETUP_CONFIRM_PASS": "Confirm the password",
"MASTER_PASS": "Master password",
"BUTTON_NEXT": "Next"
"BUTTON_NEXT": "Next",
"INCORRECT_PASSWORD": "Invalid password"
},
"COMMON": {
"BACK": "Go back"
@ -24,7 +25,8 @@
"ADD_NEW": "+ Add new",
"ACCOUNT": {
"STAKING": "Staking",
"MESSAGES": "New offers/Messages"
"MESSAGES": "New offers/Messages",
"SYNCING": "Syncing wallet"
},
"SETTINGS": "Settings",
"LOG_OUT": "Log out",
@ -42,19 +44,26 @@
"BUTTON_NEW_WALLET": "Create new wallet",
"BUTTON_OPEN_WALLET": "Open existing wallet",
"BUTTON_RESTORE_BACKUP": "Restore from backup",
"HELP": "How to create wallet?"
"HELP": "How to create wallet?",
"CHOOSE_PATH": "Please choose a path"
},
"CREATE_WALLET": {
"NAME": "Wallet name",
"PASS": "Set wallet password",
"CONFIRM": "Confirm wallet password",
"BUTTON_SELECT": "Select wallet location",
"BUTTON_CREATE": "Create wallet"
"BUTTON_CREATE": "Create wallet",
"TITLE_SAVE": "Save the wallet file.",
"ERROR_CANNOT_SAVE_TOP": "You cannot record a file on top of another file",
"ERROR_CANNOT_SAVE_SYSTEM": "You cannot save a safe file to the system partition"
},
"OPEN_WALLET": {
"NAME": "Wallet name",
"PASS": "Wallet password",
"BUTTON": "Open wallet"
"BUTTON": "Open wallet",
"WITH_ADDRESS_ALREADY_OPEN": "A wallet with this account is already open",
"SAFE_FILE_NOT_FOUND1": "Safe file not found",
"SAFE_FILE_NOT_FOUND2": "<br/><br/> It might have been renamed or moved. <br/> To open it, use the \"Open safe\" button."
},
"RESTORE_WALLET": {
"LABEL_NAME": "Wallet name",
@ -62,7 +71,9 @@
"PASS": "Wallet password",
"CONFIRM": "Confirm wallet password",
"BUTTON_SELECT": "Select wallet location",
"BUTTON_CREATE": "Create wallet"
"BUTTON_CREATE": "Create wallet",
"NOT_CORRECT_FILE_OR_PASSWORD": "Invalid safe file or password does not match",
"CHOOSE_PATH": "Please choose a path"
},
"SEED_PHRASE": {
"TITLE": "Make sure to keep your seed phrase in a safe place. If you forget your seed phrase you will not be able to recover your account.",
@ -109,7 +120,8 @@
"DETAILS": "Additional details",
"MIXIN": "Mixin",
"FEE": "Fee",
"BUTTON": "Send"
"BUTTON": "Send",
"SUCCESS_SENT": "The payment will be received within 20 minutes"
},
"HISTORY": {
"STATUS": "Status",
@ -162,13 +174,38 @@
"PROGRESS_RECEIVE": "Reply received",
"PROGRESS_COMPLETE": "Completed",
"FEE": "Fee",
"PAYMENT": "Payment ID"
"PAYMENT": "Payment ID",
"ACCEPT_STATE_WAIT_BIG": "You have accepted the contract proposal. Please wait for the pledges to be made",
"IGNORED_ACCEPT": "You have ignored the contract proposal",
"BURN_PROPOSAL": "The pledges have been nullified.",
"SUCCESS_FINISH_PROPOSAL": "The contract is complete. The payment has been sent.",
"SEND_CANCEL_PROPOSAL": "Proposal to cancel contract sent to seller",
"IGNORED_CANCEL": "You have ignored the proposal to cancel the contract",
"DEALS_CANCELED_WAIT": "The contract is being cancelled. Please wait for the pledge to be returned",
"WAITING_TIME": "Time until response"
},
"MESSAGES": {
"ADDRESS": "Address",
"MESSAGE": "Message",
"SEND_PLACEHOLDER": "Type a message...",
"SEND_BUTTON": "Send"
},
"ERRORS": {
"NOT_ENOUGH_MONEY": "Insufficient funds in account",
"CORE_BUSY": "Internal error (core is busy)",
"DAEMON_BUSY": "Internal error: deamon is busy",
"NO_MONEY_REMOVE_OFFER": "There is no fee for deleting an offer, but in order to protect the network against flood transactions you need to have at least {{fee}} {{currency}} in your safe",
"NOT_ENOUGH_OUTPUTS_TO_MIX": "For the sake of security, mixed transaction will take several days",
"TRANSACTION_IS_TO_BIG": "This transaction is large and was therefore denied by the network. Try sending the required amount in parts.",
"TRANSFER_ATTEMPT": "There is no connection to the Zano network",
"ACCESS_DENIED": "Access denied",
"TRANSACTION_ERROR": "Error. Payment not completed.",
"BAD_ARG": "Invalid argument",
"WALLET_WRONG_ID": "Invalid wallet ID",
"WRONG_PASSWORD": "Invalid password",
"FILE_RESTORED": "The safe file was corrupted somehow. We have recovered the keys and safe from the blockchain.",
"FILE_NOT_FOUND": "File not found",
"FILE_EXIST": "A file with that name already exists. Enter another name to save the file under",
"FILE_NOT_SAVED": "You cannot save a safe file in this folder. Please choose another folder."
}
}

View file

Before

Width:  |  Height:  |  Size: 644 B

After

Width:  |  Height:  |  Size: 644 B

View file

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 1024 1024" style="enable-background:new 0 0 1024 1024;" xml:space="preserve">
<style type="text/css">
.st0{fill:url(#SVGID_1_);}
.st1{fill:url(#SVGID_2_);}
.st2{fill:url(#SVGID_3_);}
</style>
<g>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="512.55" y1="984.3" x2="512.55" y2="39.3" gradientTransform="matrix(1 0 0 -1 0 1024)">
<stop offset="0" style="stop-color:#1ECED0"/>
<stop offset="0.5" style="stop-color:#8AA9F4"/>
<stop offset="1" style="stop-color:#6A44FB"/>
</linearGradient>
<polygon class="st0" points="679.6,984.7 193.5,305.1 344.4,39.7 831.6,715.3 "/>
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="217.75" y1="700.86" x2="217.75" y2="382.2152" gradientTransform="matrix(1 0 0 -1 0 1024)">
<stop offset="0" style="stop-color:#57B7E3"/>
<stop offset="1" style="stop-color:#7E8AF4;stop-opacity:0"/>
</linearGradient>
<polygon class="st1" points="193.5,305.1 435.5,643.4 0,643.4 "/>
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="807.25" y1="332.3745" x2="807.25" y2="641.9303" gradientTransform="matrix(1 0 0 -1 0 1024)">
<stop offset="0" style="stop-color:#7C83F4"/>
<stop offset="1" style="stop-color:#68B0E9;stop-opacity:0"/>
</linearGradient>
<polygon class="st2" points="831.6,715.3 590.5,381 1024,381 "/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

Before

Width:  |  Height:  |  Size: 708 B

After

Width:  |  Height:  |  Size: 708 B

View file

Before

Width:  |  Height:  |  Size: 1 KiB

After

Width:  |  Height:  |  Size: 1 KiB

View file

Before

Width:  |  Height:  |  Size: 931 B

After

Width:  |  Height:  |  Size: 931 B

View file

@ -1,6 +1,6 @@
button {
border: none;
font-family: 'Open Sans', sans-serif;
font-family: OpenSans, sans-serif;
font-size: 1.5rem;
font-weight: 600;
outline: none;
@ -116,7 +116,7 @@ button {
}
}
input[type='text'], input[type='password'] {
input[type='text'], input[type='password'], select {
border: none;
font-size: 1.4rem;
outline: none;
@ -134,7 +134,7 @@ button {
height: auto;
textarea {
font-family: 'Open Sans', sans-serif;
font-family: OpenSans, sans-serif;
border: none;
font-size: 1.4rem;
outline: none;
@ -273,6 +273,30 @@ input[type='checkbox'].style-checkbox {
}
}
.switch {
@include themify($themes) {
background-color: themed(switchBackgroundColor);
}
.circle {
&.on {
@include themify($themes) {
background-color: themed(blueTextColor);
}
}
&.off {
@include themify($themes) {
background-color: themed(optionalTextColor);
}
}
}
}
.error-block {
font-size: 1.2rem;
text-align: right;
@ -364,12 +388,32 @@ input[type='checkbox'].style-checkbox {
.modal {
@include themify($themes) {
background: themed(tooltipBackgroundColor);
background: themed(modalBackground);
color: themed(mainTextColor);
}
.content {
.icon.error {
@include themify($themes) {
background-color: themed(redTextColor);
}
}
.icon.success {
@include themify($themes) {
background-color: themed(greenTextColor);
}
}
.icon.info {
@include themify($themes) {
background-color: themed(blueTextColor);
}
}
}
.action-button {
@ -379,4 +423,52 @@ input[type='checkbox'].style-checkbox {
color: themed(alternativeTextColor);
}
}
.close-button {
.icon {
@include themify($themes) {
background-color: themed(closeButtonColor);
}
}
}
}
.ngx-contextmenu {
.dropdown-menu {
border: none;
padding: 0;
@include themify($themes) {
background-color: themed(chartOptionsBackgroundColor);
box-shadow: themed(tooltipShadow);
}
}
li {
display: block;
font-family: OpenSans, sans-serif;
font-size: 1.3rem;
text-transform: uppercase;
text-align: center;
}
a {
display: block;
padding: 0.5em 1em;
@include themify($themes) {
color: themed(mainTextColor);
}
&:hover {
@include themify($themes) {
background-color: themed(chartOptionsHoverColor);
color: themed(mainTextColor);
}
}
}
}

View file

@ -10,7 +10,8 @@ $themes: (
alternativeTextColor: #111921,
optionalTextColor: #556576,
blueTextColor: #4db1ff,
redTextColor: #ff5252,
greenTextColor: #5cda9d,
redTextColor: #fe5252,
blueButtonBackgroundColor: #4db1ff,
blueButtonHoverColor: #60b9ff,
disabledButtonBackgroundColor: #90a4ae,
@ -38,7 +39,9 @@ $themes: (
chartOptionsBackgroundColor: #2b3644,
chartOptionsHoverColor: #556576,
tooltipBackgroundColor: #42505f,
tooltipShadow: 0 0 1rem rgba(0, 0, 0, 0.5)
tooltipShadow: 0 0 1rem rgba(0, 0, 0, 0.5),
modalBackground: url(~src/assets/images/background-dark.png),
closeButtonColor: #556576
),
gray: (
bodyBackgroundColor: #101417,
@ -51,7 +54,8 @@ $themes: (
alternativeTextColor: #1a1a1a,
optionalTextColor: #565c62,
blueTextColor: #42a5f5,
redTextColor: #ff5252,
greenTextColor: #47cf8d,
redTextColor: #fe5252,
blueButtonBackgroundColor: #42a5f5,
blueButtonHoverColor: #4dafff,
disabledButtonBackgroundColor: #79848f,
@ -79,7 +83,9 @@ $themes: (
chartOptionsBackgroundColor: #292d31,
chartOptionsHoverColor: #515960,
tooltipBackgroundColor: #3e464c,
tooltipShadow: 0 0 1rem rgba(0, 0, 0, 0.5)
tooltipShadow: 0 0 1rem rgba(0, 0, 0, 0.5),
modalBackground: url(~src/assets/images/background-gray.png),
closeButtonColor: #515960
),
white: (
bodyBackgroundColor: #eeeeee,
@ -92,6 +98,7 @@ $themes: (
alternativeTextColor: #fefefe,
optionalTextColor: #a0a5ab,
blueTextColor: #2c95f1,
greenTextColor: #46c172,
redTextColor: #ff5252,
blueButtonBackgroundColor: #2c95f1,
blueButtonHoverColor: #379ffa,
@ -120,7 +127,9 @@ $themes: (
chartOptionsBackgroundColor: #e0e0e0,
chartOptionsHoverColor: #ffffff,
tooltipBackgroundColor: #ffffff,
tooltipShadow: 0 0 1rem rgba(120, 120, 120, 0.5)
tooltipShadow: 0 0 1rem rgba(120, 120, 120, 0.5),
modalBackground: url(~src/assets/images/background-white.png),
closeButtonColor: #43454b
)
);

View file

@ -81,27 +81,3 @@ app-settings {
app-login {
min-width: inherit;
}
.switch {
@include themify($themes) {
background-color: themed(switchBackgroundColor);
}
.circle {
&.on {
@include themify($themes) {
background-color: themed(blueTextColor);
}
}
&.off {
@include themify($themes) {
background-color: themed(optionalTextColor);
}
}
}
}

View file

@ -17,6 +17,7 @@
&:not(:last-child) {
position: relative;
cursor: pointer;
margin-right: 20px;
&:after {

View file

@ -0,0 +1,8 @@
[Desktop Entry]
Version=1.0
Name=Zano
Exec=Zano
Icon=/usr/share/pixmaps/desktop_linux_icon.png
MimeType=application/x-desktop
Terminal=true
Type=Application

Binary file not shown.

After

Width:  |  Height:  |  Size: 992 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 724 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -7,7 +7,6 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,600,600i,700,700i,800,800i" rel="stylesheet">
<script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script>
</head>
<body>

View file

@ -15,14 +15,44 @@
@import 'assets/scss/modules/scroll';
@import 'assets/scss/modules/table';
@font-face {
font-family: OpenSans;
src: url(~src/assets/fonts/OpenSans-Light.ttf);
font-weight: 300;
}
@font-face {
font-family: OpenSans;
src: url(~src/assets/fonts/OpenSans-Regular.ttf);
font-weight: 400;
}
@font-face {
font-family: OpenSans;
src: url(~src/assets/fonts/OpenSans-SemiBold.ttf);
font-weight: 600;
}
@font-face {
font-family: OpenSans;
src: url(~src/assets/fonts/OpenSans-Bold.ttf);
font-weight: 700;
}
@font-face {
font-family: OpenSans;
src: url(~src/assets/fonts/OpenSans-ExtraBold.ttf);
font-weight: 800;
}
html {
font-family: 'Open Sans', sans-serif;
font-family: OpenSans, sans-serif;
font-size: 10px;
}
body {
font-family: 'Open Sans', sans-serif;
font-family: OpenSans, sans-serif;
font-size: 1.6rem;
width: 100vw;
height: 100vh;
@ -48,30 +78,3 @@ body {
height: 100%;
}
}
.ngx-contextmenu .dropdown-menu {
border: solid 1px chartreuse;
background-color: darkgreen;
padding: 0;
}
.ngx-contextmenu li {
display: block;
border-top: solid 1px chartreuse;
text-transform: uppercase;
text-align: center;
}
.ngx-contextmenu li:first-child {
border-top:none;
}
.ngx-contextmenu a {
color:chartreuse;
display: block;
padding: 0.5em 1em;
}
.ngx-contextmenu a:hover {
color:darkgreen;
background-color:chartreuse;
}