1
0
Fork 0
forked from lthn/blockchain

Merge branch 'master' of github.com:hyle-team/zano

This commit is contained in:
crypro.zoidberg 2019-03-28 23:30:20 +01:00
commit b7dc0f8f65
72 changed files with 5651 additions and 354 deletions

View file

@ -18,10 +18,6 @@ cmake_gui = -D BUILD_GUI=ON
cmake_static = -D STATIC=ON
cmake_tests = -D BUILD_TESTS=ON
gui:
$(eval command += $(cmake_release) $(cmake_gui))
$(call CMAKE,$(dir_release),$(command)) && $(MAKE)
# Helper macro
define CMAKE
mkdir -p $1 && cd $1 && $2 ../../

View file

@ -162,9 +162,15 @@ if(BUILD_GUI)
set_property(TARGET Zano PROPERTY FOLDER "prog")
set_target_properties(Zano PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/gui/qt-daemon/Info.plist.in)
set_target_properties(Zano PROPERTIES VS_DEBUGGER_COMMAND_ARGUMENTS "--html-path=${CMAKE_CURRENT_SOURCE_DIR}/gui/qt-daemon/html")
set(HTML_DIR ${CMAKE_CURRENT_SOURCE_DIR}/gui/qt-daemon/html)
set_target_properties(Zano PROPERTIES VS_DEBUGGER_COMMAND_ARGUMENTS "--html-path=${HTML_DIR}")
set(CMAKE_AUTOMOC OFF)
# GUI convenience "bundle"
# set(GUI_DIR ${CMAKE_CURRENT_BINARY_DIR}/gui)
# set_target_properties(Zano PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${GUI_DIR})
# add_custom_command(TARGET Zano POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${HTML_DIR} ${GUI_DIR}/html)
endif()
if(APPLE)

View file

@ -15,7 +15,7 @@
"BACK": "Go back"
},
"BREADCRUMBS": {
"ADD_WALLET": "Add new wallet",
"ADD_WALLET": "Add wallet",
"CREATE_WALLET": "Create new wallet",
"SAVE_PHRASE": "Save your seed phrase",
"OPEN_WALLET": "Open existing wallet",
@ -30,7 +30,7 @@
},
"SIDEBAR": {
"TITLE": "Wallets",
"ADD_NEW": "+ Add new",
"ADD_NEW": "+ Add",
"ACCOUNT": {
"STAKING": "Staking",
"MESSAGES": "New offers/Messages",
@ -68,6 +68,7 @@
"FORM_ERRORS": {
"NAME_REQUIRED": "Name is required.",
"NAME_DUPLICATE": "Name is duplicate.",
"MAX_LENGTH": "Maximum name length reached.",
"CONFIRM_NOT_MATCH": "Confirm password not match."
}
},
@ -80,7 +81,8 @@
"FILE_NOT_FOUND2": "<br/><br/> It might have been renamed or moved. <br/> To open it, use the \"Open wallet\" button.",
"FORM_ERRORS": {
"NAME_REQUIRED": "Name is required.",
"NAME_DUPLICATE": "Name is duplicate."
"NAME_DUPLICATE": "Name is duplicate.",
"MAX_LENGTH": "Maximum name length reached."
}
},
"RESTORE_WALLET": {
@ -95,6 +97,7 @@
"FORM_ERRORS": {
"NAME_REQUIRED": "Name is required.",
"NAME_DUPLICATE": "Name is duplicate.",
"MAX_LENGTH": "Maximum name length reached.",
"CONFIRM_NOT_MATCH": "Confirm password not match.",
"KEY_REQUIRED": "Key is required.",
"KEY_NOT_VALID": "Key not valid."
@ -104,11 +107,24 @@
"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 wallet.",
"BUTTON_CREATE_ACCOUNT" : "Create wallet"
},
"PROGRESS": {
"ADD_WALLET": "Add wallet",
"SELECT_LOCATION": "Select wallet location",
"CREATE_WALLET": "Create new wallet",
"RESTORE_WALLET": "Restore from backup"
},
"SETTINGS": {
"TITLE": "Settings",
"DARK_THEME": "Dark theme",
"WHITE_THEME": "White theme",
"GRAY_THEME": "Grey theme",
"APP_LOCK": {
"TITLE": "Lock app after:",
"TIME1": "5 min",
"TIME2": "15 min",
"TIME3": "1 hour",
"TIME4": "Never"
},
"MASTER_PASSWORD": {
"TITLE": "Update master password",
"OLD": "Old password",
@ -145,10 +161,11 @@
"LABEL_SEED_PHRASE": "Seed phrase",
"SEED_PHRASE_HINT": "Click to reveal the seed phrase",
"BUTTON_SAVE": "Save",
"BUTTON_REMOVE": "Remove wallet",
"BUTTON_REMOVE": "Close wallet",
"FORM_ERRORS": {
"NAME_REQUIRED": "Name is required.",
"NAME_DUPLICATE": "Name is duplicate."
"NAME_DUPLICATE": "Name is duplicate.",
"MAX_LENGTH": "Maximum name length reached."
}
},
"ASSIGN_ALIAS": {
@ -170,7 +187,8 @@
"NAME_WRONG": "Alias has wrong name",
"NAME_LENGTH": "The alias must be 6-25 characters long",
"NAME_EXISTS": "Alias name already exists",
"NO_MONEY": "You do not have enough funds to assign this alias"
"NO_MONEY": "You do not have enough funds to assign this alias",
"MAX_LENGTH": "Maximum comment length reached"
},
"ONE_ALIAS": "You can create only one alias per wallet",
"REQUEST_ADD_REG": "The alias will be assigned within 10 minutes"
@ -185,7 +203,8 @@
"PLACEHOLDER": "Enter comment"
},
"FORM_ERRORS": {
"NO_MONEY": "You do not have enough funds to change the comment to this alias"
"NO_MONEY": "You do not have enough funds to change the comment to this alias",
"MAX_LENGTH": "Maximum comment length reached"
},
"COST": "Cost to edit alias {{value}} {{currency}}",
"BUTTON_EDIT": "Edit",
@ -202,7 +221,7 @@
},
"ADDRESS": {
"LABEL": "The account to which the alias will be transferred",
"PLACEHOLDER": "Enter account number"
"PLACEHOLDER": "Enter wallet address"
},
"FORM_ERRORS": {
"WRONG_ADDRESS": "No wallet with this account exists",
@ -234,7 +253,7 @@
},
"HISTORY": {
"STATUS": "Status",
"STATUS_TOOLTIP": "Approved {{current}}/{{total}}",
"STATUS_TOOLTIP": "Confirmations {{current}}/{{total}}",
"SEND": "Send",
"RECEIVED": "Received",
"DATE": "Date",
@ -336,6 +355,7 @@
"AMOUNT": "Amount",
"YOUR_DEPOSIT": "Your deposit",
"SELLER_DEPOSIT": "Seller deposit",
"BUYER_DEPOSIT": "Buyer deposit",
"SAME_AMOUNT": "Same amount",
"COMMENT": "Comment",
"DETAILS": "Additional details",
@ -347,6 +367,7 @@
"SELLER_NOT_VALID": "Seller not valid.",
"AMOUNT_REQUIRED": "Amount is required.",
"YOUR_DEPOSIT_REQUIRED": "Your deposit is required.",
"YOUR_DEPOSIT_TOO_SMALL": "Your deposit should be equal or greater than amount.",
"SELLER_DEPOSIT_REQUIRED": "Seller deposit is required.",
"SELLER_SAME": "The seller's and buyer's accounts are identical. The seller and buyer must use different wallet for the contract.",
"COMMENT_MAXIMUM": "Maximum field length reached."
@ -393,7 +414,13 @@
"BUTTON_RECEIVED": "Item received (Transfer payment and return pledge to seller)",
"BUTTON_CANCEL_BUYER": "Cancel contract (Return pledge)",
"BUTTON_NOT_CANCEL": "Do not cancel (Item shipped)",
"BUTTON_CANCEL_SELLER": "Cancel contract (Return pledge)"
"BUTTON_CANCEL_SELLER": "Cancel contract (Return pledge)",
"HOUR": "hour",
"HOURS": "hours",
"CANCEL": "Cancel",
"NULLIFY_QUESTION": "Are you sure you want to nullify your pledge and the seller's pledge?",
"BUTTON_NULLIFY_SHORT": "Nullify",
"WAITING_TIME_QUESTION": "Are you sure you want to cancel the contract?"
},
"MESSAGES": {
"ADDRESS": "Address",
@ -427,7 +454,7 @@
"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 wallet",
"NOT_ENOUGH_OUTPUTS_TO_MIX": "For the sake of security, mixed transaction will take several days",
"NOT_ENOUGH_OUTPUTS_TO_MIX": "Mix-in number is too big for current blockchain state. There are not enough unspent outputs to mix with",
"TRANSACTION_IS_TO_BIG": "Transaction exceeds network limit, send required amount with multiple transactions",
"TRANSFER_ATTEMPT": "There is no connection to Zano network",
"ACCESS_DENIED": "Access denied",

View file

@ -1,3 +1,16 @@
.app-content {
.preloader {
.loading-bar {
@include themify($themes) {
background-color: themed(progressBarFullBackgroundColor);
}
}
}
}
button {
border: none;
font-family: OpenSans, sans-serif;
@ -24,6 +37,12 @@ button {
&.blue-button:not(:disabled) {
&.error-text {
@include themify($themes) {
color: themed(redTextColor);
}
}
@include themify($themes) {
background-color: themed(blueButtonBackgroundColor);
color: themed(alternativeTextColor);
@ -143,7 +162,7 @@ button {
height: 100%;
min-height: 7.5rem;
max-height: 7.5rem;
overflow: hidden;
overflow: auto;
resize: none;
@include themify($themes) {
@ -165,6 +184,12 @@ button {
}
}
.error-text {
@include themify($themes) {
color: themed(redTextColor);
}
}
input[type='radio'].style-radio {
& + label {
@ -508,6 +533,11 @@ input[type='checkbox'].style-checkbox {
}
}
.account-tooltip {
word-break: break-word;
max-width: 18rem;
}
.ngx-contextmenu {
.dropdown-menu {
@ -546,6 +576,69 @@ input[type='checkbox'].style-checkbox {
}
}
.ng-select {
&.lock-selection-select {
width: 100%;
.ng-select-container {
border: none;
border-radius: 0;
cursor: pointer;
font-size: 1.4rem;
outline: none;
padding: 0 1rem;
height: 4.2rem;
@include themify($themes) {
background-color: themed(inputBackgroundColor);
color: themed(mainTextColor);
}
.ng-value-container {
padding: 0;
}
}
.ng-dropdown-panel {
border: none;
@include themify($themes) {
background-color: themed(inputBackgroundColor);
}
.ng-dropdown-panel-items {
.ng-option {
font-size: 1.4rem;
padding: 1rem;
@include themify($themes) {
background-color: themed(inputBackgroundColor);
color: themed(mainTextColor);
}
&.ng-option-marked {
@include themify($themes) {
background-color: themed(selectHoverColor);
color: themed(mainTextColor);
}
}
&.ng-option-selected {
@include themify($themes) {
background-color: themed(selectSelectedColor);
color: themed(mainTextColor);
}
}
}
}
}
}
}
app-modal-container {
.modal {
@ -635,3 +728,27 @@ app-transaction-details {
}
}
}
app-progress-container {
.progress-bar-container {
@include themify($themes) {
color: themed(mainTextColor);
}
.progress-bar {
@include themify($themes) {
background-color: themed(progressBarBackgroundColor);
}
.progress-bar-full {
@include themify($themes) {
background-color: themed(progressBarFullBackgroundColor);
}
}
}
}
}

View file

@ -22,6 +22,8 @@ $themes: (
turquoiseButtonHoverColor: #52d9ea,
transparentButtonBorderColor: #2b3644,
inputBackgroundColor: #171e27,
selectHoverColor: rgba(58, 72, 90, 0.5),
selectSelectedColor: rgba(43, 54, 68, 0.5),
switchBackgroundColor: #000000,
accountBackgroundColor: rgba(43, 54, 68, 0.5),
accountHoverBackgroundColor: rgba(58, 72, 90, 0.5),
@ -66,6 +68,8 @@ $themes: (
turquoiseButtonHoverColor: #43cee0,
transparentButtonBorderColor: #2f3438,
inputBackgroundColor: #292d31,
selectHoverColor: rgba(70, 76, 81, 0.5),
selectSelectedColor: rgba(37, 40, 43, 0.5),
switchBackgroundColor: #000000,
accountBackgroundColor: rgba(37, 40, 43, 0.5),
accountHoverBackgroundColor: rgba(70, 76, 81, 0.5),
@ -110,6 +114,8 @@ $themes: (
turquoiseButtonHoverColor: #2bbdcf,
transparentButtonBorderColor: #ebebeb,
inputBackgroundColor: #e6e6e6,
selectHoverColor: rgba(240, 240, 240, 0.5),
selectSelectedColor: rgba(224, 224, 224, 0.5),
switchBackgroundColor: #e0e0e0,
accountBackgroundColor: rgba(30, 136, 229, 1),
accountHoverBackgroundColor: rgba(240, 240, 240, 0.5),

View file

@ -75,6 +75,37 @@ app-settings {
color: themed(optionalTextColor);
}
}
.scale-selection {
.button-block {
@include themify($themes) {
background-color: themed(tabInactiveBackgroundColor);
}
.label {
@include themify($themes) {
color: themed(optionalTextColor);
}
}
&.active {
@include themify($themes) {
background-color: themed(blueTextColor);
}
.label {
@include themify($themes) {
color: themed(blueTextColor);
}
}
}
}
}
}
}

View file

@ -138,16 +138,37 @@ app-sidebar {
border-bottom: 0.2rem solid themed(sidebarBorderColor);
}
button {
.wrap-button {
@include themify($themes) {
color: themed(mainTextColor);
}
.icon {
button {
@include themify($themes) {
background-color: themed(blueTextColor);
color: themed(mainTextColor);
}
.icon {
@include themify($themes) {
background-color: themed(blueTextColor);
}
}
}
&.active {
button {
@include themify($themes) {
background-color: themed(accountBackgroundColor)!important;
color: themed(accountMainTextColor)!important;
}
.icon {
@include themify($themes) {
background-color: themed(accountIndicatorBackgroundColor)!important;
}
}
}
}
}

View file

@ -19,6 +19,7 @@
position: relative;
cursor: pointer;
margin-right: 20px;
outline-style: none;
&:after {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -23,6 +23,7 @@
"@angular/platform-browser": "~7.0.0",
"@angular/platform-browser-dynamic": "~7.0.0",
"@angular/router": "~7.0.0",
"@ng-select/ng-select": "^2.16.2",
"@ngx-translate/core": "^11.0.0",
"@ngx-translate/http-loader": "^4.0.0",
"angular-highcharts": "^7.0.2",
@ -39,7 +40,7 @@
"devDependencies": {
"@angular-devkit/build-angular": "^0.12.2",
"@angular/cli": "~7.0.2",
"@angular/compiler-cli": "~7.0.0",
"@angular/compiler-cli": "^7.2.10",
"@angular/language-service": "~7.0.0",
"@types/highcharts": "^5.0.34",
"@types/jasmine": "~2.8.8",

View file

@ -0,0 +1,8 @@
import { InputDisableSelectionDirective } from './input-disable-selection.directive';
describe('InputDisableSelectionDirective', () => {
it('should create an instance', () => {
const directive = new InputDisableSelectionDirective();
expect(directive).toBeTruthy();
});
});

View file

@ -0,0 +1,16 @@
import {Directive, HostListener} from '@angular/core';
@Directive({
selector: 'input'
})
export class InputDisableSelectionDirective {
constructor() {}
@HostListener('mousedown', ['$event'])
handleInput(event: Event) {
if ((<HTMLInputElement>event.target).readOnly) {
event.preventDefault();
}
}
}

View file

@ -43,6 +43,8 @@
.message-container {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
margin-left: 2rem;
.title {

View file

@ -0,0 +1,10 @@
<div class="progress-bar-container">
<div class="progress-bar">
<div class="progress-bar-full" [style.width]="width"></div>
</div>
<div class="progress-labels">
<span *ngFor="let label of labels">
{{ label | translate }}
</span>
</div>
</div>

View file

@ -0,0 +1,50 @@
.progress-bar-container {
position: absolute;
bottom: 0;
left: 0;
padding: 0 3rem;
width: 100%;
height: 3rem;
.progress-bar {
position: absolute;
top: -0.7rem;
left: 0;
margin: 0 3rem;
width: calc(100% - 6rem);
height: 0.7rem;
.progress-bar-full {
height: 0.7rem;
}
}
.progress-labels {
display: flex;
align-items: center;
justify-content: space-between;
font-size: 1.2rem;
height: 100%;
span {
flex: 1 0 0;
text-align: center;
&:first-child {
text-align: left;
}
&:last-child {
text-align: right;
}
}
}
.progress-time {
position: absolute;
top: -3rem;
left: 50%;
transform: translateX(-50%);
font-size: 1.2rem;
}
}

View file

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ProgressContainerComponent } from './progress-container.component';
describe('ProgressContainerComponent', () => {
let component: ProgressContainerComponent;
let fixture: ComponentFixture<ProgressContainerComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ProgressContainerComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ProgressContainerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View file

@ -0,0 +1,17 @@
import { Component, Input, OnInit } from '@angular/core';
@Component({
selector: 'app-progress-container',
templateUrl: './progress-container.component.html',
styleUrls: ['./progress-container.component.scss']
})
export class ProgressContainerComponent implements OnInit {
@Input() width: string;
@Input() labels: [];
constructor() {}
ngOnInit() {}
}

View file

@ -119,7 +119,7 @@ export class Wallet {
}
}
if (!exists) {
if (this.history.length && items[i].timestamp > this.history[0].timestamp) {
if (this.history.length && items[i].timestamp >= this.history[0].timestamp) {
this.history.unshift(this.prepareHistoryItem(items[i]));
} else {
this.history.push(this.prepareHistoryItem(items[i]));

View file

@ -50,7 +50,7 @@ export class ContractStatusMessagesPipe implements PipeTransform {
state.part1 = this.translate.instant('CONTRACTS.STATUS_MESSAGES.SELLER.EXPIRED');
break;
}
return state.part1 + ' ' + state.part2;
return state.part1 + (state.part2.length ? '. ' + state.part2 : '');
}
getStateBuyer(stateNum: number): string {
@ -101,7 +101,7 @@ export class ContractStatusMessagesPipe implements PipeTransform {
state.part1 = this.translate.instant('CONTRACTS.STATUS_MESSAGES.BUYER.EXPIRED');
break;
}
return state.part1 + ' ' + state.part2;
return state.part1 + (state.part2.length ? '. ' + state.part2 : '');
}
transform(item: any, args?: any): any {

View file

@ -582,6 +582,12 @@ export class BackendService {
this.runCommand('get_tx_pool_info', {}, callback);
}
getVersion(callback) {
this.runCommand('get_version', {}, (status, version) => {
callback(version);
});
}
}
@ -615,11 +621,7 @@ export class BackendService {
this.runCommand('reset_wallet_password', {wallet_id: wallet_id, pass: pass}, callback);
},
getVersion: function (callback) {
this.runCommand('get_version', {}, function (status, version) {
callback(version)
})
},
getOsVersion: function (callback) {
this.runCommand('get_os_version', {}, function (status, version) {

View file

@ -29,7 +29,9 @@ export class VariablesService {
public default_fee_big = new BigNumber('10000000000');
public settings = {
appLockTime: 15,
theme: '',
scale: 10,
language: 'en',
default_path: '/',
viewedContracts: [],
@ -41,6 +43,8 @@ export class VariablesService {
public aliases: any = [];
public aliasesChecked: any = {};
public enableAliasSearch = false;
public maxWalletNameLength = 25;
public maxCommentLength = 255;
getHeightAppEvent = new BehaviorSubject(null);
getRefreshStackingEvent = new BehaviorSubject(null);
@ -48,7 +52,6 @@ export class VariablesService {
public idle = new Idle()
.whenNotInteractive()
.within(15)
.do(() => {
this.ngZone.run(() => {
this.idle.stop();
@ -59,6 +62,7 @@ export class VariablesService {
public allContextMenu: ContextMenuComponent;
public onlyCopyContextMenu: ContextMenuComponent;
public pasteSelectContextMenu: ContextMenuComponent;
constructor(private router: Router, private ngZone: NgZone, private contextMenuService: ContextMenuService) {
}
@ -96,13 +100,17 @@ export class VariablesService {
}
startCountdown() {
this.idle.start();
this.idle.within(this.settings.appLockTime).start();
}
stopCountdown() {
this.idle.stop();
}
restartCountdown() {
this.idle.within(this.settings.appLockTime).restart();
}
public onContextMenu($event: MouseEvent): void {
$event.target['contextSelectionStart'] = $event.target['selectionStart'];
$event.target['contextSelectionEnd'] = $event.target['selectionEnd'];
@ -127,4 +135,23 @@ export class VariablesService {
$event.stopPropagation();
}
public onContextMenuPasteSelect($event: MouseEvent): void {
$event.target['contextSelectionStart'] = $event.target['selectionStart'];
$event.target['contextSelectionEnd'] = $event.target['selectionEnd'];
console.warn($event.target);
console.warn($event.target['disabled']);
if ($event.target && ($event.target['nodeName'].toUpperCase() === 'TEXTAREA' || $event.target['nodeName'].toUpperCase() === 'INPUT') && !$event.target['readOnly']) {
this.contextMenuService.show.next({
contextMenu: this.pasteSelectContextMenu,
event: $event,
item: $event.target,
});
$event.preventDefault();
$event.stopPropagation();
}
}
}

View file

@ -1,10 +1,15 @@
<app-sidebar *ngIf="variablesService.appPass"></app-sidebar>
<div class="app-content scrolled-content">
<router-outlet></router-outlet>
<router-outlet *ngIf="[0, 1, 2].indexOf(variablesService.daemon_state) !== -1"></router-outlet>
<div class="preloader" *ngIf="[3, 4, 5].indexOf(variablesService.daemon_state) !== -1">
<span *ngIf="variablesService.daemon_state === 3">{{ 'SIDEBAR.SYNCHRONIZATION.LOADING' | translate }}</span>
<span *ngIf="variablesService.daemon_state === 4">{{ 'SIDEBAR.SYNCHRONIZATION.ERROR' | translate }}</span>
<span *ngIf="variablesService.daemon_state === 5">{{ 'SIDEBAR.SYNCHRONIZATION.COMPLETE' | translate }}</span>
<span class="loading-bar"></span>
</div>
</div>
<context-menu #allContextMenu>
<ng-template contextMenuItem (execute)="contextMenuCopy($event.item)">{{ 'CONTEXT_MENU.COPY' | translate }}</ng-template>
<ng-template contextMenuItem (execute)="contextMenuPaste($event.item)">{{ 'CONTEXT_MENU.PASTE' | translate }}</ng-template>
@ -14,3 +19,8 @@
<context-menu #onlyCopyContextMenu>
<ng-template contextMenuItem (execute)="contextMenuOnlyCopy($event.item)">{{ 'CONTEXT_MENU.COPY' | translate }}</ng-template>
</context-menu>
<context-menu #pasteSelectContextMenu>
<ng-template contextMenuItem (execute)="contextMenuPaste($event.item)">{{ 'CONTEXT_MENU.PASTE' | translate }}</ng-template>
<ng-template contextMenuItem (execute)="contextMenuSelect($event.item)">{{ 'CONTEXT_MENU.SELECT' | translate }}</ng-template>
</context-menu>

View file

@ -5,4 +5,54 @@
overflow-x: overlay;
overflow-y: hidden;
width: 100%;
.preloader {
align-self: center;
color: #fff;
font-size: 2rem;
margin: 0 auto;
text-align: center;
width: 50%;
.loading-bar {
display: block;
animation: move 5s linear infinite;
background-image:
-webkit-gradient(
linear, 0 0, 100% 100%,
color-stop(.125, rgba(0, 0, 0, .15)), color-stop(.125, transparent),
color-stop(.250, transparent), color-stop(.250, rgba(0, 0, 0, .10)),
color-stop(.375, rgba(0, 0, 0, .10)), color-stop(.375, transparent),
color-stop(.500, transparent), color-stop(.500, rgba(0, 0, 0, .15)),
color-stop(.625, rgba(0, 0, 0, .15)), color-stop(.625, transparent),
color-stop(.750, transparent), color-stop(.750, rgba(0, 0, 0, .10)),
color-stop(.875, rgba(0, 0, 0, .10)), color-stop(.875, transparent),
to(transparent)
),
-webkit-gradient(
linear, 0 100%, 100% 0,
color-stop(.125, rgba(0, 0, 0, .30)), color-stop(.125, transparent),
color-stop(.250, transparent), color-stop(.250, rgba(0, 0, 0, .25)),
color-stop(.375, rgba(0, 0, 0, .25)), color-stop(.375, transparent),
color-stop(.500, transparent), color-stop(.500, rgba(0, 0, 0, .30)),
color-stop(.625, rgba(0, 0, 0, .30)), color-stop(.625, transparent),
color-stop(.750, transparent), color-stop(.750, rgba(0, 0, 0, .25)),
color-stop(.875, rgba(0, 0, 0, .25)), color-stop(.875, transparent),
to(transparent)
);
background-size: 10rem 10rem;
margin-top: 2rem;
width: 100%;
height: 1rem;
}
}
@keyframes move {
0% {
background-position: 100% -10rem;
}
100% {
background-position: 100% 10rem;
}
}
}

View file

@ -75,6 +75,7 @@ export class AppComponent implements OnInit, OnDestroy {
this.ngZone.run(() => {
this.router.navigate(['/']);
});
this.variablesService.daemon_state = 5;
this.backend.storeSecureAppData(() => {
this.backend.storeAppData(() => {
const recursionCloseWallets = () => {
@ -472,6 +473,9 @@ export class AppComponent implements OnInit, OnDestroy {
} else {
this.renderer.addClass(document.body, 'theme-' + this.variablesService.defaultTheme);
}
if (this.variablesService.settings.hasOwnProperty('scale') && [7.5, 10, 12.5, 15].indexOf(this.variablesService.settings.scale) !== -1) {
this.renderer.setStyle(document.documentElement, 'font-size', this.variablesService.settings.scale + 'px');
}
} else {
this.variablesService.settings.theme = this.variablesService.defaultTheme;
this.renderer.addClass(document.body, 'theme-' + this.variablesService.settings.theme);

View file

@ -30,6 +30,7 @@ import { HttpClient, HttpClientModule } from '@angular/common/http';
import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { NgSelectModule } from '@ng-select/ng-select';
import { BackendService } from './_helpers/services/backend.service';
import { ModalService } from './_helpers/services/modal.service';
@ -51,6 +52,8 @@ export function HttpLoaderFactory(httpClient: HttpClient) {
import { ChartModule, HIGHCHARTS_MODULES, Highcharts} from 'angular-highcharts';
import { ProgressContainerComponent } from './_helpers/directives/progress-container/progress-container.component';
import { InputDisableSelectionDirective } from './_helpers/directives/input-disable-selection/input-disable-selection.directive';
// import * as more from 'highcharts/highcharts-more.src';
// import * as exporting from 'highcharts/modules/exporting.src';
// import * as highstock from 'highcharts/modules/stock.src';
@ -94,7 +97,9 @@ Highcharts.setOptions({
TooltipDirective,
InputValidateDirective,
ModalContainerComponent,
TransactionDetailsComponent
TransactionDetailsComponent,
ProgressContainerComponent,
InputDisableSelectionDirective
],
imports: [
BrowserModule,
@ -109,6 +114,7 @@ Highcharts.setOptions({
}),
FormsModule,
ReactiveFormsModule,
NgSelectModule,
ChartModule,
ContextMenuModule.forRoot()
],

View file

@ -5,7 +5,7 @@
<span [routerLink]="['/wallet/' + wallet.wallet_id + '/history']">{{ wallet.name }}</span>
<span>{{ 'BREADCRUMBS.ASSIGN_ALIAS' | translate }}</span>
</div>
<button class="back-btn" (click)="back()">
<button type="button" class="back-btn" (click)="back()">
<i class="icon back"></i>
<span>{{ 'COMMON.BACK' | translate }}</span>
</button>
@ -45,7 +45,16 @@
<label for="alias-comment" tooltip="{{ 'ASSIGN_ALIAS.COMMENT.TOOLTIP' | translate }}" placement="bottom-left" tooltipClass="table-tooltip assign-alias-tooltip" [delay]="500">
{{ 'ASSIGN_ALIAS.COMMENT.LABEL' | translate }}
</label>
<textarea id="alias-comment" formControlName="comment" placeholder="{{ 'ASSIGN_ALIAS.COMMENT.PLACEHOLDER' | translate }}" (contextmenu)="variablesService.onContextMenu($event)"></textarea>
<textarea id="alias-comment"
class="scrolled-content"
formControlName="comment"
placeholder="{{ 'ASSIGN_ALIAS.COMMENT.PLACEHOLDER' | translate }}"
[maxLength]="variablesService.maxCommentLength"
(contextmenu)="variablesService.onContextMenu($event)">
</textarea>
<div class="error-block" *ngIf="assignForm.get('comment').value.length >= variablesService.maxCommentLength">
{{ 'ASSIGN_ALIAS.FORM_ERRORS.MAX_LENGTH' | translate }}
</div>
</div>
<div class="alias-cost">{{ "ASSIGN_ALIAS.COST" | translate : {value: alias.price | intToMoney, currency: variablesService.defaultCurrency} }}</div>

View file

@ -21,7 +21,13 @@ export class AssignAliasComponent implements OnInit, OnDestroy {
wallet: Wallet;
assignForm = new FormGroup({
name: new FormControl('', [Validators.required, Validators.pattern(/^@?[a-z0-9\.\-]{6,25}$/)]),
comment: new FormControl('')
comment: new FormControl('', [(g: FormControl) => {
if (g.value > this.variablesService.maxCommentLength) {
return {'maxLength': true};
} else {
return null;
}
}])
});
assignFormSubscription: Subscription;
alias = {

View file

@ -31,7 +31,7 @@
<div>{{item.private_detailes.to_pay | intToMoney}} {{variablesService.defaultCurrency}}</div>
</td>
<td>
<div class="status" tooltip="{{ item | contractStatusMessages }}" placement="top" tooltipClass="table-tooltip" [delay]="500">
<div class="status" [class.error-text]="item.state === 4" tooltip="{{ item | contractStatusMessages }}" placement="top" tooltipClass="table-tooltip" [delay]="500">
{{item | contractStatusMessages}}
</div>
</td>

View file

@ -68,8 +68,10 @@
}
.status, .comment {
display: inline-block;
text-overflow: ellipsis;
overflow: hidden;
max-width: 100%;
}
}
}

View file

@ -5,17 +5,17 @@
<span [routerLink]="['/main']">{{ 'BREADCRUMBS.ADD_WALLET' | translate }}</span>
<span>{{ 'BREADCRUMBS.CREATE_WALLET' | translate }}</span>
</div>
<a class="back-btn" [routerLink]="['/main']">
<button type="button" class="back-btn" [routerLink]="['/main']">
<i class="icon back"></i>
<span>{{ 'COMMON.BACK' | translate }}</span>
</a>
</button>
</div>
<form class="form-create" [formGroup]="createForm">
<div class="input-block">
<label for="wallet-name">{{ 'CREATE_WALLET.NAME' | translate }}</label>
<input type="text" id="wallet-name" formControlName="name" [attr.disabled]="walletSaved ? '' : null">
<input type="text" id="wallet-name" formControlName="name" [attr.readonly]="walletSaved ? '' : null" [maxlength]="variablesService.maxWalletNameLength" (contextmenu)="variablesService.onContextMenu($event)">
<div class="error-block" *ngIf="createForm.controls['name'].invalid && (createForm.controls['name'].dirty || createForm.controls['name'].touched)">
<div *ngIf="createForm.controls['name'].errors['required']">
{{ 'CREATE_WALLET.FORM_ERRORS.NAME_REQUIRED' | translate }}
@ -24,16 +24,19 @@
{{ 'CREATE_WALLET.FORM_ERRORS.NAME_DUPLICATE' | translate }}
</div>
</div>
<div class="error-block" *ngIf="createForm.get('name').value.length >= variablesService.maxWalletNameLength">
{{ 'CREATE_WALLET.FORM_ERRORS.MAX_LENGTH' | translate }}
</div>
</div>
<div class="input-block">
<label for="wallet-password">{{ 'CREATE_WALLET.PASS' | translate }}</label>
<input type="password" id="wallet-password" formControlName="password" [attr.disabled]="walletSaved ? '' : null">
<input type="password" id="wallet-password" formControlName="password" [attr.readonly]="walletSaved ? '' : null" (contextmenu)="variablesService.onContextMenuPasteSelect($event)">
</div>
<div class="input-block">
<label for="confirm-wallet-password">{{ 'CREATE_WALLET.CONFIRM' | translate }}</label>
<input type="password" id="confirm-wallet-password" formControlName="confirm" [attr.disabled]="walletSaved ? '' : null">
<input type="password" id="confirm-wallet-password" formControlName="confirm" [attr.readonly]="walletSaved ? '' : null" (contextmenu)="variablesService.onContextMenuPasteSelect($event)">
<div class="error-block" *ngIf="createForm.controls['password'].dirty && createForm.controls['confirm'].dirty && createForm.errors">
<div *ngIf="createForm.errors['confirm_mismatch']">
{{ 'CREATE_WALLET.FORM_ERRORS.CONFIRM_NOT_MATCH' | translate }}
@ -42,7 +45,7 @@
</div>
<div class="wrap-buttons">
<button type="button" class="transparent-button" *ngIf="walletSaved" disabled><i class="icon"></i>{{createForm.controls['name'].value}}</button>
<button type="button" class="transparent-button" *ngIf="walletSaved" disabled><i class="icon"></i>{{walletSavedName}}</button>
<button type="button" class="blue-button select-button" (click)="saveWallet()" [disabled]="!createForm.valid" *ngIf="!walletSaved">{{ 'CREATE_WALLET.BUTTON_SELECT' | translate }}</button>
<button type="button" class="blue-button create-button" (click)="createWallet()" [disabled]="!walletSaved">{{ 'CREATE_WALLET.BUTTON_CREATE' | translate }}</button>
</div>
@ -50,3 +53,5 @@
</form>
</div>
<app-progress-container [width]="progressWidth" [labels]="['PROGRESS.ADD_WALLET', 'PROGRESS.SELECT_LOCATION', 'PROGRESS.CREATE_WALLET']"></app-progress-container>

View file

@ -1,3 +1,7 @@
:host {
position: relative;
}
.form-create {
margin: 2.4rem 0;
width: 50%;

View file

@ -34,6 +34,8 @@ export class CreateWalletComponent implements OnInit {
};
walletSaved = false;
walletSavedName = '';
progressWidth = '9rem';
constructor(
private router: Router,
@ -50,15 +52,17 @@ export class CreateWalletComponent implements OnInit {
createWallet() {
this.ngZone.run(() => {
this.progressWidth = '100%';
this.router.navigate(['/seed-phrase'], {queryParams: {wallet_id: this.wallet.id}});
});
}
saveWallet() {
if (this.createForm.valid) {
if (this.createForm.valid && this.createForm.get('name').value.length <= this.variablesService.maxWalletNameLength) {
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.walletSavedName = file_data.path.substr(file_data.path.lastIndexOf('/') + 1, file_data.path.length - 1);
this.backend.generateWallet(file_data.path, this.createForm.get('password').value, (generate_status, generate_data, errorCode) => {
if (generate_status) {
this.wallet.id = generate_data.wallet_id;
@ -75,6 +79,7 @@ export class CreateWalletComponent implements OnInit {
);
this.ngZone.run(() => {
this.walletSaved = true;
this.progressWidth = '50%';
});
} else {
if (errorCode && errorCode === 'ALREADY_EXISTS') {

View file

@ -5,7 +5,7 @@
<span [routerLink]="['/wallet/' + wallet.wallet_id + '/history']">{{ wallet.name }}</span>
<span>{{ 'BREADCRUMBS.EDIT_ALIAS' | translate }}</span>
</div>
<button class="back-btn" (click)="back()">
<button type="button" class="back-btn" (click)="back()">
<i class="icon back"></i>
<span>{{ 'COMMON.BACK' | translate }}</span>
</button>
@ -24,16 +24,26 @@
<label for="alias-comment">
{{ 'EDIT_ALIAS.COMMENT.LABEL' | translate }}
</label>
<textarea id="alias-comment" [(ngModel)]="alias.comment" [ngModelOptions]="{standalone: true}" placeholder="{{ 'EDIT_ALIAS.COMMENT.PLACEHOLDER' | translate }}" (contextmenu)="variablesService.onContextMenu($event)"></textarea>
<textarea id="alias-comment"
class="scrolled-content"
[(ngModel)]="alias.comment"
[ngModelOptions]="{standalone: true}"
[maxlength]="variablesService.maxCommentLength"
(contextmenu)="variablesService.onContextMenu($event)"
placeholder="{{ 'EDIT_ALIAS.COMMENT.PLACEHOLDER' | translate }}">
</textarea>
<div class="error-block" *ngIf="alias.comment.length > 0 && notEnoughMoney">
{{ 'EDIT_ALIAS.FORM_ERRORS.NO_MONEY' | translate }}
</div>
<div class="error-block" *ngIf="alias.comment.length >= variablesService.maxCommentLength">
{{ 'EDIT_ALIAS.FORM_ERRORS.MAX_LENGTH' | translate }}
</div>
</div>
<div class="alias-cost">{{ "EDIT_ALIAS.COST" | translate : {value: variablesService.default_fee, currency: variablesService.defaultCurrency} }}</div>
<div class="wrap-buttons">
<button type="button" class="blue-button" (click)="updateAlias()" [disabled]="notEnoughMoney || oldAliasComment === alias.comment">{{ 'EDIT_ALIAS.BUTTON_EDIT' | translate }}</button>
<button type="button" class="blue-button" (click)="updateAlias()" [disabled]="notEnoughMoney || (oldAliasComment === alias.comment) || alias.comment.length > variablesService.maxCommentLength">{{ 'EDIT_ALIAS.BUTTON_EDIT' | translate }}</button>
<button type="button" class="blue-button" (click)="back()">{{ 'EDIT_ALIAS.BUTTON_CANCEL' | translate }}</button>
</div>

View file

@ -41,7 +41,7 @@ export class EditAliasComponent implements OnInit {
}
updateAlias() {
if (this.requestProcessing || this.notEnoughMoney || this.oldAliasComment === this.alias.comment) {
if (this.requestProcessing || this.notEnoughMoney || this.oldAliasComment === this.alias.comment || this.alias.comment.length > this.variablesService.maxCommentLength) {
return;
}
this.requestProcessing = true;

View file

@ -8,7 +8,7 @@
<div class="input-block">
<label for="master-pass">{{ 'LOGIN.SETUP_MASTER_PASS' | translate }}</label>
<input type="password" id="master-pass" formControlName="password">
<input type="password" id="master-pass" formControlName="password" (contextmenu)="variablesService.onContextMenuPasteSelect($event)">
<div class="error-block" *ngIf="regForm.controls['password'].invalid && (regForm.controls['password'].dirty || regForm.controls['password'].touched)">
<div *ngIf="regForm.controls['password'].errors['required']">
{{ 'LOGIN.FORM_ERRORS.PASS_REQUIRED' | translate }}
@ -18,7 +18,7 @@
<div class="input-block">
<label for="confirm-pass">{{ 'LOGIN.SETUP_CONFIRM_PASS' | translate }}</label>
<input type="password" id="confirm-pass" formControlName="confirmation">
<input type="password" id="confirm-pass" formControlName="confirmation" (contextmenu)="variablesService.onContextMenuPasteSelect($event)">
<div class="error-block" *ngIf="regForm.controls['confirmation'].invalid && (regForm.controls['confirmation'].dirty || regForm.controls['confirmation'].touched)">
<div *ngIf="regForm.controls['confirmation'].errors['required']">
{{ 'LOGIN.FORM_ERRORS.CONFIRM_REQUIRED' | translate }}
@ -39,7 +39,7 @@
<div class="input-block">
<label for="master-pass-login">{{ 'LOGIN.MASTER_PASS' | translate }}</label>
<input type="password" id="master-pass-login" formControlName="password" autofocus>
<input type="password" id="master-pass-login" formControlName="password" autofocus (contextmenu)="variablesService.onContextMenuPasteSelect($event)">
<div class="error-block" *ngIf="authForm.controls['password'].invalid && (authForm.controls['password'].dirty || authForm.controls['password'].touched)">
<div *ngIf="authForm.controls['password'].errors['required']">
{{ 'LOGIN.FORM_ERRORS.PASS_REQUIRED' | translate }}

View file

@ -81,45 +81,43 @@ export class LoginComponent implements OnInit, OnDestroy {
this.backend.openWallet(wallet.path, wallet.pass, true, (open_status, open_data) => {
if (open_status) {
openWallets++;
this.ngZone.run(() => {
const new_wallet = new Wallet(
open_data.wallet_id,
wallet.name,
wallet.pass,
open_data['wi'].path,
open_data['wi'].address,
open_data['wi'].balance,
open_data['wi'].unlocked_balance,
open_data['wi'].mined_total,
open_data['wi'].tracking_hey
);
new_wallet.alias = this.backend.getWalletAlias(new_wallet.address);
if (open_data.recent_history && open_data.recent_history.history) {
new_wallet.prepareHistory(open_data.recent_history.history);
}
this.backend.getContracts(open_data.wallet_id, (contracts_status, contracts_data) => {
if (contracts_status && contracts_data.hasOwnProperty('contracts')) {
this.ngZone.run(() => {
new_wallet.prepareContractsAfterOpen(contracts_data.contracts, this.variablesService.exp_med_ts, this.variablesService.height_app, this.variablesService.settings.viewedContracts, this.variablesService.settings.notViewedContracts);
});
}
});
this.variablesService.wallets.push(new_wallet);
if (this.variablesService.wallets.length === 1) {
this.router.navigate(['/wallet/' + this.variablesService.wallets[0].wallet_id]);
}
});
this.backend.runWallet(open_data.wallet_id, (run_status) => {
if (run_status) {
runWallets++;
this.ngZone.run(() => {
const new_wallet = new Wallet(
open_data.wallet_id,
wallet.name,
wallet.pass,
open_data['wi'].path,
open_data['wi'].address,
open_data['wi'].balance,
open_data['wi'].unlocked_balance,
open_data['wi'].mined_total,
open_data['wi'].tracking_hey
);
new_wallet.alias = this.backend.getWalletAlias(new_wallet.address);
if (open_data.recent_history && open_data.recent_history.history) {
new_wallet.prepareHistory(open_data.recent_history.history);
}
this.backend.getContracts(open_data.wallet_id, (contracts_status, contracts_data) => {
if (contracts_status && contracts_data.hasOwnProperty('contracts')) {
this.ngZone.run(() => {
new_wallet.prepareContractsAfterOpen(contracts_data.contracts, this.variablesService.exp_med_ts, this.variablesService.height_app, this.variablesService.settings.viewedContracts, this.variablesService.settings.notViewedContracts);
});
}
});
this.variablesService.wallets.push(new_wallet);
if (this.variablesService.wallets.length === 1) {
this.router.navigate(['/wallet/' + this.variablesService.wallets[0].wallet_id]);
}
});
} else {
if (wallet_index === data.length - 1 && runWallets === 0) {
this.ngZone.run(() => {
this.router.navigate(['/']);
});
}
// console.log(run_data['error_code']);
}
});
} else {

View file

@ -1,4 +1,12 @@
<div class="content">
<div class="head" *ngIf="variablesService.wallets.length > 0">
<button type="button" class="back-btn" (click)="back()">
<i class="icon back"></i>
<span>{{ 'COMMON.BACK' | translate }}</span>
</button>
</div>
<div class="add-wallet">
<h3 class="add-wallet-title">{{ 'MAIN.TITLE' | translate }}</h3>
<div class="add-wallet-buttons">
@ -10,4 +18,5 @@
<i class="icon"></i><span>{{ 'MAIN.HELP' | translate }}</span>
</div>
</div>
</div>

View file

@ -6,6 +6,10 @@
.content {
padding: 3rem;
min-height: 100%;
.head {
justify-content: flex-end;
}
}
.add-wallet {

View file

@ -1,4 +1,5 @@
import {Component, NgZone, OnInit} from '@angular/core';
import {Location} from "@angular/common";
import {BackendService} from '../_helpers/services/backend.service';
import {VariablesService} from '../_helpers/services/variables.service';
import {Router} from '@angular/router';
@ -13,6 +14,7 @@ export class MainComponent implements OnInit {
constructor(
private router: Router,
private location: Location,
private backend: BackendService,
private variablesService: VariablesService,
private ngZone: NgZone,
@ -35,7 +37,11 @@ export class MainComponent implements OnInit {
}
openInBrowser() {
this.backend.openUrlInBrowser('zano.org');
this.backend.openUrlInBrowser('docs.zano.org/v1.0/docs/how-to-create-wallet');
}
back() {
this.location.back()
}
}

View file

@ -5,17 +5,17 @@
<span [routerLink]="['/main']">{{ 'BREADCRUMBS.ADD_WALLET' | translate }}</span>
<span>{{ 'BREADCRUMBS.OPEN_WALLET' | translate }}</span>
</div>
<a class="back-btn" [routerLink]="['/main']">
<button type="button" class="back-btn" [routerLink]="['/main']">
<i class="icon back"></i>
<span>{{ 'COMMON.BACK' | translate }}</span>
</a>
</button>
</div>
<form class="form-open" [formGroup]="openForm">
<div class="input-block">
<label for="wallet-name">{{ 'OPEN_WALLET.NAME' | translate }}</label>
<input type="text" id="wallet-name" formControlName="name">
<input type="text" id="wallet-name" formControlName="name" [maxLength]="variablesService.maxWalletNameLength" (contextmenu)="variablesService.onContextMenu($event)">
<div class="error-block" *ngIf="openForm.controls['name'].invalid && (openForm.controls['name'].dirty || openForm.controls['name'].touched)">
<div *ngIf="openForm.controls['name'].errors['required']">
{{ 'OPEN_WALLET.FORM_ERRORS.NAME_REQUIRED' | translate }}
@ -24,11 +24,14 @@
{{ 'OPEN_WALLET.FORM_ERRORS.NAME_DUPLICATE' | translate }}
</div>
</div>
<div class="error-block" *ngIf="openForm.get('name').value.length >= variablesService.maxWalletNameLength">
{{ 'OPEN_WALLET.FORM_ERRORS.MAX_LENGTH' | translate }}
</div>
</div>
<div class="input-block">
<label for="wallet-password">{{ 'OPEN_WALLET.PASS' | translate }}</label>
<input type="password" id="wallet-password" formControlName="password">
<input type="password" id="wallet-password" formControlName="password" (contextmenu)="variablesService.onContextMenuPasteSelect($event)">
</div>
<div class="wrap-buttons">

View file

@ -60,7 +60,7 @@ export class OpenWalletComponent implements OnInit, OnDestroy {
}
openWallet() {
if (this.openForm.valid) {
if (this.openForm.valid && this.openForm.get('name').value.length <= this.variablesService.maxWalletNameLength) {
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') {
let error_translate = this.translate.instant('OPEN_WALLET.FILE_NOT_FOUND1');
@ -85,31 +85,31 @@ export class OpenWalletComponent implements OnInit, OnDestroy {
});
});
} else {
const new_wallet = new Wallet(
open_data.wallet_id,
this.openForm.get('name').value,
this.openForm.get('password').value,
open_data['wi'].path,
open_data['wi'].address,
open_data['wi'].balance,
open_data['wi'].unlocked_balance,
open_data['wi'].mined_total,
open_data['wi'].tracking_hey
);
new_wallet.alias = this.backend.getWalletAlias(new_wallet.address);
if (open_data.recent_history && open_data.recent_history.history) {
new_wallet.prepareHistory(open_data.recent_history.history);
}
this.backend.getContracts(open_data.wallet_id, (contracts_status, contracts_data) => {
if (contracts_status && contracts_data.hasOwnProperty('contracts')) {
this.ngZone.run(() => {
new_wallet.prepareContractsAfterOpen(contracts_data.contracts, this.variablesService.exp_med_ts, this.variablesService.height_app, this.variablesService.settings.viewedContracts, this.variablesService.settings.notViewedContracts);
});
}
});
this.variablesService.wallets.push(new_wallet);
this.backend.runWallet(open_data.wallet_id, (run_status, run_data) => {
if (run_status) {
const new_wallet = new Wallet(
open_data.wallet_id,
this.openForm.get('name').value,
this.openForm.get('password').value,
open_data['wi'].path,
open_data['wi'].address,
open_data['wi'].balance,
open_data['wi'].unlocked_balance,
open_data['wi'].mined_total,
open_data['wi'].tracking_hey
);
new_wallet.alias = this.backend.getWalletAlias(new_wallet.address);
if (open_data.recent_history && open_data.recent_history.history) {
new_wallet.prepareHistory(open_data.recent_history.history);
}
this.backend.getContracts(open_data.wallet_id, (contracts_status, contracts_data) => {
if (contracts_status && contracts_data.hasOwnProperty('contracts')) {
this.ngZone.run(() => {
new_wallet.prepareContractsAfterOpen(contracts_data.contracts, this.variablesService.exp_med_ts, this.variablesService.height_app, this.variablesService.settings.viewedContracts, this.variablesService.settings.notViewedContracts);
});
}
});
this.variablesService.wallets.push(new_wallet);
this.backend.storeSecureAppData((status, data) => {
console.log('Store App Data', status, data);
});

View file

@ -30,7 +30,7 @@
<div class="input-blocks-row">
<div class="input-block">
<label for="purchase-seller">{{ 'PURCHASE.SELLER' | translate }}</label>
<input type="text" id="purchase-seller" formControlName="seller" [readonly]="!newPurchase" (contextmenu)="variablesService.onContextMenu($event)">
<input type="text" id="purchase-seller" formControlName="seller" [readonly]="!newPurchase" appInputDisableSelection (contextmenu)="(!newPurchase) ? variablesService.onContextMenuOnlyCopy($event, purchaseForm.controls['seller'].value) : variablesService.onContextMenu($event)">
<div class="error-block" *ngIf="purchaseForm.controls['seller'].invalid && (purchaseForm.controls['seller'].dirty || purchaseForm.controls['seller'].touched)">
<div *ngIf="purchaseForm.controls['seller'].errors['required']">
{{ 'PURCHASE.FORM_ERRORS.SELLER_REQUIRED' | translate }}
@ -57,18 +57,21 @@
<div class="input-blocks-row">
<div class="input-block">
<label for="purchase-your-deposit">{{ 'PURCHASE.YOUR_DEPOSIT' | translate }}</label>
<label for="purchase-your-deposit">{{ ( (currentContract && !currentContract.is_a) ? 'PURCHASE.BUYER_DEPOSIT' : 'PURCHASE.YOUR_DEPOSIT') | translate }}</label>
<input type="text" id="purchase-your-deposit" formControlName="yourDeposit" appInputValidate="money" [readonly]="!newPurchase" (contextmenu)="variablesService.onContextMenu($event)">
<div class="error-block" *ngIf="purchaseForm.controls['yourDeposit'].invalid && (purchaseForm.controls['yourDeposit'].dirty || purchaseForm.controls['yourDeposit'].touched)">
<div *ngIf="purchaseForm.controls['yourDeposit'].errors['required']">
{{ 'PURCHASE.FORM_ERRORS.YOUR_DEPOSIT_REQUIRED' | translate }}
</div>
</div>
<div class="error-block" *ngIf="purchaseForm.invalid && (purchaseForm.controls['yourDeposit'].dirty || purchaseForm.controls['amount'].touched) && purchaseForm.errors && purchaseForm.errors['your_deposit_too_small']">
{{ 'PURCHASE.FORM_ERRORS.YOUR_DEPOSIT_TOO_SMALL' | translate }}
</div>
</div>
<div class="input-block">
<div class="wrap-label">
<label for="purchase-seller-deposit">{{ 'PURCHASE.SELLER_DEPOSIT' | translate }}</label>
<label for="purchase-seller-deposit">{{ ( (currentContract && !currentContract.is_a) ? 'PURCHASE.YOUR_DEPOSIT' : 'PURCHASE.SELLER_DEPOSIT') | translate }}</label>
<div class="checkbox-block">
<input type="checkbox" id="purchase-same-amount" class="style-checkbox" formControlName="sameAmount" (change)="sameAmountChange()">
<label for="purchase-same-amount">{{ 'PURCHASE.SAME_AMOUNT' | translate }}</label>
@ -148,7 +151,7 @@
<span *ngIf="currentContract.state == 3">{{ 'PURCHASE.RECEIVED' | translate }}</span>
<span *ngIf="currentContract.state == 4">{{ 'PURCHASE.NOT_RECEIVED' | translate }}</span>
<span *ngIf="currentContract.state == 4">{{ 'PURCHASE.NULLIFIED' | translate }}</span>
<span *ngIf="currentContract.state == 4" class="error-text">{{ 'PURCHASE.NULLIFIED' | translate }}</span>
<span *ngIf="currentContract.state == 5">{{ 'PURCHASE.PROPOSAL_CANCEL_SELLER' | translate }}</span>
<!--<span *ngIf="currentContract.state == 5" ng-bind="'(' + (contract.cancel_expiration_time | buyingTime : 2) + ')'"></span>-->
@ -178,7 +181,7 @@
<span *ngIf="currentContract.state == 3">{{ 'PURCHASE.RECEIVED' | translate }}</span>
<span *ngIf="currentContract.state == 4">{{ 'PURCHASE.NOT_RECEIVED' | translate }}</span>
<span *ngIf="currentContract.state == 4">{{ 'PURCHASE.NULLIFIED' | translate }}</span>
<span *ngIf="currentContract.state == 4" class="error-text">{{ 'PURCHASE.NULLIFIED' | translate }}</span>
<span *ngIf="currentContract.state == 5">{{ 'PURCHASE.PROPOSAL_CANCEL_BUYER' | translate }}</span>
<!--<span *ngIf="currentContract.state == 5" ng-bind="'(' + (contract.cancel_expiration_time | buyingTime : 1) + ')'"></span>-->
@ -206,14 +209,14 @@
<button type="button" class="turquoise-button" (click)="ignoredContract();">{{'PURCHASE.BUTTON_IGNORE' | translate}}</button>
</ng-container>
<ng-container *ngIf="currentContract.is_a && (currentContract.state == 201 || currentContract.state == 2 || currentContract.state == 120 || currentContract.state == 130)">
<button type="button" class="blue-button" (click)="productNotGot();" [disabled]="currentContract.cancel_expiration_time == 0 && (currentContract.height == 0 || (variablesService.height_app - currentContract.height) < 10)">
<ng-container *ngIf="!showNullify && !showTimeSelect && currentContract.is_a && (currentContract.state == 201 || currentContract.state == 2 || currentContract.state == 120 || currentContract.state == 130)">
<button type="button" class="blue-button error-text" (click)="showNullify = true;" [disabled]="currentContract.cancel_expiration_time == 0 && (currentContract.height == 0 || (variablesService.height_app - currentContract.height) < 10)">
{{'PURCHASE.BUTTON_NULLIFY' | translate}}
</button>
<button type="button" class="turquoise-button" (click)="dealsDetailsFinish();" [disabled]="currentContract.cancel_expiration_time == 0 && (currentContract.height == 0 || (variablesService.height_app - currentContract.height) < 10)">
{{'PURCHASE.BUTTON_RECEIVED' | translate}}
</button>
<button type="button" class="green-button" (click)="dealsDetailsCancel();" [disabled]="currentContract.cancel_expiration_time == 0 && (currentContract.height == 0 || (variablesService.height_app - currentContract.height) < 10)">
<button type="button" class="green-button" (click)="showTimeSelect = true;" [disabled]="currentContract.cancel_expiration_time == 0 && (currentContract.height == 0 || (variablesService.height_app - currentContract.height) < 10)">
{{'PURCHASE.BUTTON_CANCEL_BUYER' | translate}}
</button>
</ng-container>
@ -225,14 +228,30 @@
</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="nullify-block-row" *ngIf="showNullify">
<div class="input-block">
<div>{{'PURCHASE.NULLIFY_QUESTION' | translate}}</div>
<div class="nullify-block">
<button type="button" class="blue-button" (click)="showNullify = false;">{{ 'PURCHASE.CANCEL' | translate }}</button>
<button type="button" class="blue-button" (click)="productNotGot();">{{ 'PURCHASE.BUTTON_NULLIFY_SHORT' | translate }}</button>
</div>
</div>
</div>
<div class="time-cancel-block-row" *ngIf="showTimeSelect && !newPurchase && currentContract.is_a && (currentContract.state == 201 || currentContract.state == 2 || currentContract.state == 120 || currentContract.state == 130)">
<div class="input-block">
<div>{{ 'PURCHASE.WAITING_TIME_QUESTION' | translate }}</div>
<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 value="1">1 {{ 'PURCHASE.HOUR' | translate }}</option>
<option *ngFor="let title of [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}} {{ 'PURCHASE.HOURS' | translate }}
</option>
</select>
<div class="time-cancel-block">
<button type="button" class="blue-button" (click)="showTimeSelect = false;">{{ 'PURCHASE.CANCEL' | translate }}</button>
<button type="button" class="blue-button" (click)="dealsDetailsCancel();">{{ 'PURCHASE.BUTTON_CANCEL_BUYER' | translate }}</button>
</div>
</div>
</div>

View file

@ -110,6 +110,49 @@
margin: 0 0.5rem;
}
}
.nullify-block-row {
display: flex;
justify-content: center;
.input-block {
align-items: center;
.nullify-block {
margin: 1rem 0;
.blue-button {
margin: 0 0.5rem;
}
}
}
}
.time-cancel-block-row {
display: flex;
justify-content: center;
.input-block {
align-items: center;
margin-bottom: 0;
select {
width: auto;
}
.time-cancel-block {
display: flex;
flex-direction: row;
align-items: flex-start;
margin: 1rem 0;
.blue-button {
margin: 0 0.5rem;
}
}
}
}
}
.progress-bar-container {

View file

@ -7,6 +7,7 @@ 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';
import {BigNumber} from 'bignumber.js';
@Component({
selector: 'app-purchase',
@ -56,11 +57,15 @@ export class PurchaseComponent implements OnInit, OnDestroy {
time: new FormControl({value: '12', disabled: false}),
timeCancel: new FormControl({value: '12', disabled: false}),
payment: new FormControl('')
}, function (g: FormGroup) {
return (new BigNumber(g.get('yourDeposit').value)).isLessThan(g.get('amount').value) ? {'your_deposit_too_small': true} : null;
});
additionalOptions = false;
currentContract = null;
heightAppEvent;
showTimeSelect = false;
showNullify = false;
constructor(
private route: ActivatedRoute,
@ -153,13 +158,13 @@ export class PurchaseComponent implements OnInit, OnDestroy {
this.currentContract.is_new = true;
this.variablesService.currentWallet.recountNewContracts();
}
if (!this.newPurchase && this.currentContract.is_a && (this.currentContract.state === 201 || this.currentContract.state === 2 || this.currentContract.state === 120 || this.currentContract.state === 130)) {
if (this.currentContract.cancel_expiration_time === 0 && (this.currentContract.height === 0 || (this.variablesService.height_app - this.currentContract.height) < 10)) {
this.purchaseForm.get('timeCancel').disable();
} else {
this.purchaseForm.get('timeCancel').enable();
}
}
// if (!this.newPurchase && this.currentContract.is_a && (this.currentContract.state === 201 || this.currentContract.state === 2 || this.currentContract.state === 120 || this.currentContract.state === 130)) {
// if (this.currentContract.cancel_expiration_time === 0 && (this.currentContract.height === 0 || (this.variablesService.height_app - this.currentContract.height) < 10)) {
// this.purchaseForm.get('timeCancel').disable();
// } else {
// this.purchaseForm.get('timeCancel').enable();
// }
// }
});
}

View file

@ -5,17 +5,17 @@
<span [routerLink]="['/main']">{{ 'BREADCRUMBS.ADD_WALLET' | translate }}</span>
<span>{{ 'BREADCRUMBS.RESTORE_WALLET' | translate }}</span>
</div>
<a class="back-btn" [routerLink]="['/main']">
<button type="button" class="back-btn" [routerLink]="['/main']">
<i class="icon back"></i>
<span>{{ 'COMMON.BACK' | translate }}</span>
</a>
</button>
</div>
<form class="form-restore" [formGroup]="restoreForm">
<div class="input-block half-block">
<label for="wallet-name">{{ 'RESTORE_WALLET.LABEL_NAME' | translate }}</label>
<input type="text" id="wallet-name" formControlName="name" [attr.disabled]="walletSaved ? '' : null">
<input type="text" id="wallet-name" formControlName="name" [attr.readonly]="walletSaved ? '' : null" [maxLength]="variablesService.maxWalletNameLength" (contextmenu)="variablesService.onContextMenu($event)">
<div class="error-block" *ngIf="restoreForm.controls['name'].invalid && (restoreForm.controls['name'].dirty || restoreForm.controls['name'].touched)">
<div *ngIf="restoreForm.controls['name'].errors['required']">
{{ 'RESTORE_WALLET.FORM_ERRORS.NAME_REQUIRED' | translate }}
@ -24,16 +24,19 @@
{{ 'RESTORE_WALLET.FORM_ERRORS.NAME_DUPLICATE' | translate }}
</div>
</div>
<div class="error-block" *ngIf="restoreForm.get('name').value.length >= variablesService.maxWalletNameLength">
{{ 'RESTORE_WALLET.FORM_ERRORS.MAX_LENGTH' | translate }}
</div>
</div>
<div class="input-block half-block">
<label for="wallet-password">{{ 'RESTORE_WALLET.PASS' | translate }}</label>
<input type="password" id="wallet-password" formControlName="password" [attr.disabled]="walletSaved ? '' : null">
<input type="password" id="wallet-password" formControlName="password" [attr.readonly]="walletSaved ? '' : null" (contextmenu)="variablesService.onContextMenuPasteSelect($event)">
</div>
<div class="input-block half-block">
<label for="confirm-wallet-password">{{ 'RESTORE_WALLET.CONFIRM' | translate }}</label>
<input type="password" id="confirm-wallet-password" formControlName="confirm" [attr.disabled]="walletSaved ? '' : null">
<input type="password" id="confirm-wallet-password" formControlName="confirm" [attr.readonly]="walletSaved ? '' : null" (contextmenu)="variablesService.onContextMenuPasteSelect($event)">
<div class="error-block" *ngIf="restoreForm.controls['password'].dirty && restoreForm.controls['confirm'].dirty && restoreForm.errors">
<div *ngIf="restoreForm.errors['confirm_mismatch']">
{{ 'RESTORE_WALLET.FORM_ERRORS.CONFIRM_NOT_MATCH' | translate }}
@ -43,7 +46,7 @@
<div class="input-block">
<label for="phrase-key">{{ 'RESTORE_WALLET.LABEL_PHRASE_KEY' | translate }}</label>
<input type="text" id="phrase-key" formControlName="key" [attr.disabled]="walletSaved ? '' : null" (contextmenu)="variablesService.onContextMenu($event)">
<input type="text" id="phrase-key" formControlName="key" [attr.readonly]="walletSaved ? '' : null" (contextmenu)="variablesService.onContextMenu($event)">
<div class="error-block" *ngIf="restoreForm.controls['key'].invalid && (restoreForm.controls['key'].dirty || restoreForm.controls['key'].touched)">
<div *ngIf="restoreForm.controls['key'].errors['required']">
{{ 'RESTORE_WALLET.FORM_ERRORS.KEY_REQUIRED' | translate }}
@ -55,7 +58,7 @@
</div>
<div class="wrap-buttons">
<button type="button" class="transparent-button" *ngIf="walletSaved">{{restoreForm.controls['name'].value}}</button>
<button type="button" class="transparent-button" *ngIf="walletSaved" disabled><i class="icon"></i>{{walletSavedName}}</button>
<button type="button" class="blue-button select-button" (click)="saveWallet()" [disabled]="!restoreForm.valid" *ngIf="!walletSaved">{{ 'RESTORE_WALLET.BUTTON_SELECT' | translate }}</button>
<button type="button" class="blue-button create-button" (click)="createWallet()" [disabled]="!walletSaved">{{ 'RESTORE_WALLET.BUTTON_CREATE' | translate }}</button>
</div>
@ -63,3 +66,5 @@
</form>
</div>
<app-progress-container [width]="progressWidth" [labels]="['PROGRESS.ADD_WALLET', 'PROGRESS.SELECT_LOCATION', 'PROGRESS.RESTORE_WALLET']"></app-progress-container>

View file

@ -1,3 +1,7 @@
:host {
position: relative;
}
.form-restore {
margin: 2.4rem 0;
width: 100%;

View file

@ -35,6 +35,8 @@ export class RestoreWalletComponent implements OnInit {
};
walletSaved = false;
walletSavedName = '';
progressWidth = '9rem';
constructor(
private router: Router,
@ -52,12 +54,13 @@ export class RestoreWalletComponent implements OnInit {
createWallet() {
this.ngZone.run(() => {
this.progressWidth = '100%';
this.router.navigate(['/seed-phrase'], {queryParams: {wallet_id: this.wallet.id}});
});
}
saveWallet() {
if (this.restoreForm.valid) {
if (this.restoreForm.valid && this.restoreForm.get('name').value.length <= this.variablesService.maxWalletNameLength) {
this.backend.isValidRestoreWalletText(this.restoreForm.get('key').value, (valid_status, valid_data) => {
if (valid_data === 'FALSE') {
@ -68,6 +71,7 @@ export class RestoreWalletComponent implements OnInit {
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.walletSavedName = save_data.path.substr(save_data.path.lastIndexOf('/') + 1, save_data.path.length - 1);
this.backend.restoreWallet(save_data.path, this.restoreForm.get('password').value, this.restoreForm.get('key').value, (restore_status, restore_data) => {
if (restore_status) {
this.wallet.id = restore_data.wallet_id;
@ -95,6 +99,7 @@ export class RestoreWalletComponent implements OnInit {
});
this.ngZone.run(() => {
this.walletSaved = true;
this.progressWidth = '50%';
});
} else {
this.modalService.prepareModal('error', 'RESTORE_WALLET.NOT_CORRECT_FILE_OR_PASSWORD');

View file

@ -5,10 +5,10 @@
<span [routerLink]="['/main']">{{ 'BREADCRUMBS.ADD_WALLET' | translate }}</span>
<span>{{ 'BREADCRUMBS.SAVE_PHRASE' | translate }}</span>
</div>
<a class="back-btn" [routerLink]="['/main']">
<button type="button" class="back-btn" (click)="back()">
<i class="icon back"></i>
<span>{{ 'COMMON.BACK' | translate }}</span>
</a>
</button>
</div>
<h3 class="seed-phrase-title">{{ 'SEED_PHRASE.TITLE' | translate }}</h3>
@ -19,6 +19,8 @@
</ng-container>
</div>
<button type="button" class="blue-button" (click)="runWallet()">{{ 'SEED_PHRASE.BUTTON_CREATE_ACCOUNT' | translate }}</button>
<button type="button" class="blue-button seed-phrase-button" (click)="runWallet()">{{ 'SEED_PHRASE.BUTTON_CREATE_ACCOUNT' | translate }}</button>
</div>
<app-progress-container [width]="'100%'" [labels]="['PROGRESS.ADD_WALLET', 'PROGRESS.SELECT_LOCATION', 'PROGRESS.CREATE_WALLET']"></app-progress-container>

View file

@ -1,3 +1,7 @@
:host {
position: relative;
}
.seed-phrase-title {
line-height: 2.2rem;
padding: 2.2rem 0;
@ -17,7 +21,7 @@
}
}
button {
.seed-phrase-button {
margin: 2.8rem 0;
width: 25%;
min-width: 1.5rem;

View file

@ -1,4 +1,5 @@
import {Component, NgZone, OnDestroy, OnInit} from '@angular/core';
import {Location} from "@angular/common";
import {BackendService} from '../_helpers/services/backend.service';
import {ActivatedRoute, Router} from '@angular/router';
import {VariablesService} from '../_helpers/services/variables.service';
@ -18,6 +19,7 @@ export class SeedPhraseComponent implements OnInit, OnDestroy {
constructor(
private route: ActivatedRoute,
private router: Router,
private location: Location,
private backend: BackendService,
private variablesService: VariablesService,
private modalService: ModalService,
@ -72,6 +74,10 @@ export class SeedPhraseComponent implements OnInit, OnDestroy {
}
}
back() {
this.location.back();
}
ngOnDestroy() {
this.queryRouting.unsubscribe();
}

View file

@ -24,15 +24,40 @@
</div>
</div>
<div class="scale-selection">
<button type="button" class="button-block" [class.active]="item.id === variablesService.settings.scale" *ngFor="let item of appScaleOptions" (click)="setScale(item.id)">
<span class="label">{{item.name}}</span>
</button>
</div>
<div class="lock-selection">
<label class="lock-selection-title">{{ 'SETTINGS.APP_LOCK.TITLE' | translate }}</label>
<ng-select class="lock-selection-select"
[items]="appLockOptions"
bindValue="id"
bindLabel="name"
[(ngModel)]="variablesService.settings.appLockTime"
[clearable]="false"
[searchable]="false"
(change)="onLockChange()">
<ng-template ng-label-tmp let-item="item">
{{item.name | translate}}
</ng-template>
<ng-template ng-option-tmp let-item="item" let-index="index">
{{item.name | translate}}
</ng-template>
</ng-select>
</div>
<form class="master-password" [formGroup]="changeForm" (ngSubmit)="onSubmitChangePass()">
<span class="master-password-title">{{ 'SETTINGS.MASTER_PASSWORD.TITLE' | translate }}</span>
<div class="input-block">
<label for="old-password">{{ 'SETTINGS.MASTER_PASSWORD.OLD' | translate }}</label>
<input type="password" id="old-password" formControlName="password"/>
<input type="password" id="old-password" formControlName="password" (contextmenu)="variablesService.onContextMenuPasteSelect($event)"/>
<div class="error-block" *ngIf="changeForm.controls['password'].invalid && (changeForm.controls['password'].dirty || changeForm.controls['password'].touched)">
<div *ngIf="changeForm.controls['password'].errors.required">
<div *ngIf="changeForm.controls['password'].errors['required']">
{{ 'SETTINGS.FORM_ERRORS.PASS_REQUIRED' | translate }}
</div>
</div>
@ -43,9 +68,9 @@
<div class="input-block">
<label for="new-password">{{ 'SETTINGS.MASTER_PASSWORD.NEW' | translate }}</label>
<input type="password" id="new-password" formControlName="new_password"/>
<input type="password" id="new-password" formControlName="new_password" (contextmenu)="variablesService.onContextMenuPasteSelect($event)"/>
<div class="error-block" *ngIf="changeForm.controls['new_password'].invalid && (changeForm.controls['new_password'].dirty || changeForm.controls['new_password'].touched)">
<div *ngIf="changeForm.controls['new_password'].errors.required">
<div *ngIf="changeForm.controls['new_password'].errors['required']">
{{ 'SETTINGS.FORM_ERRORS.PASS_REQUIRED' | translate }}
</div>
</div>
@ -53,9 +78,9 @@
<div class="input-block">
<label for="confirm-password">{{ 'SETTINGS.MASTER_PASSWORD.CONFIRM' | translate }}</label>
<input type="password" id="confirm-password" formControlName="new_confirmation"/>
<input type="password" id="confirm-password" formControlName="new_confirmation" (contextmenu)="variablesService.onContextMenuPasteSelect($event)"/>
<div class="error-block" *ngIf="changeForm.controls['new_confirmation'].invalid && (changeForm.controls['new_confirmation'].dirty || changeForm.controls['new_confirmation'].touched)">
<div *ngIf="changeForm.controls['new_confirmation'].errors.required">
<div *ngIf="changeForm.controls['new_confirmation'].errors['required']">
{{ 'SETTINGS.FORM_ERRORS.PASS_REQUIRED' | translate }}
</div>
</div>
@ -68,6 +93,6 @@
</form>
<div class="last-build">{{ 'SETTINGS.LAST_BUILD' | translate : {value: variablesService.last_build_available} }}</div>
<div class="last-build">{{ 'SETTINGS.LAST_BUILD' | translate : {value: currentBuild} }}</div>
</div>

View file

@ -22,6 +22,50 @@
}
}
.lock-selection {
display: flex;
flex-direction: column;
align-items: flex-start;
margin: 2.4rem 0;
width: 50%;
.lock-selection-title {
display: flex;
font-size: 1.5rem;
line-height: 2.7rem;
margin-bottom: 1rem;
}
}
.scale-selection {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 0 4rem;
width: 50%;
height: 0.5rem;
.button-block {
position: relative;
display: flex;
align-items: center;
justify-content: center;
flex: 1 0 auto;
margin: 0 0.2rem;
padding: 0;
height: 0.5rem;
.label {
position: absolute;
bottom: -1rem;
left: 50%;
transform: translate(-50%, 100%);
font-size: 1rem;
white-space: nowrap;
}
}
}
.master-password {
width: 50%;
@ -42,6 +86,6 @@
.last-build {
position: absolute;
bottom: 3rem;
right: 3rem;
font-size: 1.3rem;
left: 3rem;
font-size: 1rem;
}

View file

@ -1,4 +1,4 @@
import {Component, OnInit, Renderer2} from '@angular/core';
import {Component, NgZone, OnInit, Renderer2} from '@angular/core';
import {VariablesService} from '../_helpers/services/variables.service';
import {BackendService} from '../_helpers/services/backend.service';
import {FormControl, FormGroup, Validators} from '@angular/forms';
@ -10,11 +10,58 @@ import {Location} from '@angular/common';
styleUrls: ['./settings.component.scss']
})
export class SettingsComponent implements OnInit {
theme: string;
changeForm: any;
constructor(private renderer: Renderer2, private variablesService: VariablesService, private backend: BackendService, private location: Location) {
theme: string;
scale: number;
changeForm: any;
appLockOptions = [
{
id: 5,
name: 'SETTINGS.APP_LOCK.TIME1'
},
{
id: 15,
name: 'SETTINGS.APP_LOCK.TIME2'
},
{
id: 60,
name: 'SETTINGS.APP_LOCK.TIME3'
},
{
id: 0,
name: 'SETTINGS.APP_LOCK.TIME4'
}
];
appScaleOptions = [
{
id: 7.5,
name: '75% scale'
},
{
id: 10,
name: '100% scale'
},
{
id: 12.5,
name: '125% scale'
},
{
id: 15,
name: '150% scale'
}
];
currentBuild = '';
constructor(
private renderer: Renderer2,
public variablesService: VariablesService,
private backend: BackendService,
private location: Location,
private ngZone: NgZone
) {
this.theme = this.variablesService.settings.theme;
this.scale = this.variablesService.settings.scale;
this.changeForm = new FormGroup({
password: new FormControl('', Validators.required),
new_password: new FormControl('', Validators.required),
@ -26,7 +73,13 @@ export class SettingsComponent implements OnInit {
}]);
}
ngOnInit() {}
ngOnInit() {
this.backend.getVersion((version) => {
this.ngZone.run(() => {
this.currentBuild = version;
});
});
}
setTheme(theme) {
this.renderer.removeClass(document.body, 'theme-' + this.theme);
@ -36,6 +89,13 @@ export class SettingsComponent implements OnInit {
this.backend.storeAppData();
}
setScale(scale) {
this.scale = scale;
this.variablesService.settings.scale = this.scale;
this.renderer.setStyle(document.documentElement, 'font-size', this.scale + 'px');
this.backend.storeAppData();
}
onSubmitChangePass() {
if (this.changeForm.valid) {
this.variablesService.appPass = this.changeForm.get('new_password').value;
@ -49,6 +109,11 @@ export class SettingsComponent implements OnInit {
}
}
onLockChange() {
this.variablesService.restartCountdown();
this.backend.storeAppData();
}
back() {
this.location.back();
}

View file

@ -5,14 +5,14 @@
<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 + '/history']">
<div class="sidebar-account-row account-title-balance">
<span class="title">{{wallet.name}}</span>
<span class="title" tooltip="{{ wallet.name }}" placement="top-left" tooltipClass="table-tooltip account-tooltip" [delay]="500" [showWhenNoOverflow]="false">{{wallet.name}}</span>
<span class="balance">{{wallet.balance | intToMoney : '3' }} {{variablesService.defaultCurrency}}</span>
</div>
<div class="sidebar-account-row account-alias">
<div style="display: flex; align-items: center;">
<span>{{wallet.alias['name']}}</span>
<ng-container *ngIf="wallet.alias['comment'] && wallet.alias['comment'].length">
<i class="icon comment" tooltip="{{wallet.alias['comment']}}" placement="top" tooltipClass="table-tooltip" [delay]="500"></i>
<i class="icon comment" tooltip="{{wallet.alias['comment']}}" placement="top" tooltipClass="table-tooltip account-tooltip" [delay]="500"></i>
</ng-container>
</div>
<span>$ {{wallet.getMoneyEquivalent(variablesService.moneyEquivalent) | intToMoney | number : '1.2-2'}}</span>
@ -38,14 +38,18 @@
</div>
</div>
<div class="sidebar-settings">
<button [routerLink]="['/settings']" routerLinkActive="active">
<i class="icon settings"></i>
<span>{{ 'SIDEBAR.SETTINGS' | translate }}</span>
</button>
<button (click)="logOut()">
<i class="icon logout"></i>
<span>{{ 'SIDEBAR.LOG_OUT' | translate }}</span>
</button>
<div class="wrap-button" routerLinkActive="active">
<button [routerLink]="['/settings']">
<i class="icon settings"></i>
<span>{{ 'SIDEBAR.SETTINGS' | translate }}</span>
</button>
</div>
<div class="wrap-button">
<button (click)="logOut()">
<i class="icon logout"></i>
<span>{{ 'SIDEBAR.LOG_OUT' | translate }}</span>
</button>
</div>
</div>
<div class="sidebar-synchronization-status">
<div class="status-container">

View file

@ -4,6 +4,7 @@
justify-content: space-between;
flex: 0 0 25rem;
padding: 0 3rem 3rem;
max-width: 25rem;
}
.sidebar-accounts {
@ -54,11 +55,15 @@
.title {
font-size: 1.5rem;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.balance {
font-size: 1.8rem;
font-weight: 600;
white-space: nowrap;
}
}
@ -99,9 +104,9 @@
justify-content: center;
border-radius: 1rem;
font-size: 1rem;
min-width: 24px;
height: 16px;
padding: 0 5px;
min-width: 2.4rem;
height: 1.6rem;
padding: 0 0.5rem;
}
}
@ -150,27 +155,32 @@
flex: 0 0 auto;
padding-bottom: 1rem;
button {
display: flex;
align-items: center;
background: transparent;
border: none;
line-height: 3rem;
outline: none;
padding: 0;
font-weight: 400;
.wrap-button {
margin: 0 -3rem;
.icon {
margin-right: 1.2rem;
width: 1.7rem;
height: 1.7rem;
button {
display: flex;
align-items: center;
background: transparent;
border: none;
font-weight: 400;
line-height: 3rem;
outline: none;
padding: 0 3rem;
width: 100%;
&.settings {
mask: url(../../assets/icons/settings.svg) no-repeat center;
}
.icon {
margin-right: 1.2rem;
width: 1.7rem;
height: 1.7rem;
&.logout {
mask: url(../../assets/icons/logout.svg) no-repeat center;
&.settings {
mask: url(../../assets/icons/settings.svg) no-repeat center;
}
&.logout {
mask: url(../../assets/icons/logout.svg) no-repeat center;
}
}
}
}
@ -235,8 +245,41 @@
}
.loading {
background-image: url("../../assets/images/loading.png");
animation: move 5s linear infinite;
background-image:
-webkit-gradient(
linear, 0 0, 100% 100%,
color-stop(.125, rgba(0, 0, 0, .15)), color-stop(.125, transparent),
color-stop(.250, transparent), color-stop(.250, rgba(0, 0, 0, .10)),
color-stop(.375, rgba(0, 0, 0, .10)), color-stop(.375, transparent),
color-stop(.500, transparent), color-stop(.500, rgba(0, 0, 0, .15)),
color-stop(.625, rgba(0, 0, 0, .15)), color-stop(.625, transparent),
color-stop(.750, transparent), color-stop(.750, rgba(0, 0, 0, .10)),
color-stop(.875, rgba(0, 0, 0, .10)), color-stop(.875, transparent),
to(transparent)
),
-webkit-gradient(
linear, 0 100%, 100% 0,
color-stop(.125, rgba(0, 0, 0, .30)), color-stop(.125, transparent),
color-stop(.250, transparent), color-stop(.250, rgba(0, 0, 0, .25)),
color-stop(.375, rgba(0, 0, 0, .25)), color-stop(.375, transparent),
color-stop(.500, transparent), color-stop(.500, rgba(0, 0, 0, .30)),
color-stop(.625, rgba(0, 0, 0, .30)), color-stop(.625, transparent),
color-stop(.750, transparent), color-stop(.750, rgba(0, 0, 0, .25)),
color-stop(.875, rgba(0, 0, 0, .25)), color-stop(.875, transparent),
to(transparent)
);
background-size: 7rem 7rem;
height: 100%;
}
}
}
@keyframes move {
0% {
background-position: 100% -7rem;
}
100% {
background-position: 100% 7rem;
}
}

View file

@ -5,7 +5,7 @@
<span [routerLink]="['/wallet/' + wallet.wallet_id + '/history']">{{ wallet.name }}</span>
<span>{{ 'BREADCRUMBS.TRANSFER_ALIAS' | translate }}</span>
</div>
<button class="back-btn" (click)="back()">
<button type="button" class="back-btn" (click)="back()">
<i class="icon back"></i>
<span>{{ 'COMMON.BACK' | translate }}</span>
</button>

View file

@ -15,7 +15,7 @@
<div class="input-block">
<label for="wallet-name">{{ 'WALLET_DETAILS.LABEL_NAME' | translate }}</label>
<input type="text" id="wallet-name" formControlName="name">
<input type="text" id="wallet-name" formControlName="name" [maxLength]="variablesService.maxWalletNameLength" (contextmenu)="variablesService.onContextMenu($event)">
<div class="error-block" *ngIf="detailsForm.controls['name'].invalid && (detailsForm.controls['name'].dirty || detailsForm.controls['name'].touched)">
<div *ngIf="detailsForm.controls['name'].errors['required']">
{{ 'WALLET_DETAILS.FORM_ERRORS.NAME_REQUIRED' | translate }}
@ -24,6 +24,9 @@
{{ 'WALLET_DETAILS.FORM_ERRORS.NAME_DUPLICATE' | translate }}
</div>
</div>
<div class="error-block" *ngIf="detailsForm.get('name').value.length >= variablesService.maxWalletNameLength">
{{ 'WALLET_DETAILS.FORM_ERRORS.MAX_LENGTH' | translate }}
</div>
</div>
<div class="input-block">

View file

@ -1,6 +1,6 @@
<div class="header">
<div>
<h3>{{variablesService.currentWallet.name}}</h3>
<h3 tooltip="{{ variablesService.currentWallet.name }}" placement="bottom-left" tooltipClass="table-tooltip" [delay]="500" [showWhenNoOverflow]="false">{{variablesService.currentWallet.name}}</h3>
<!--<button (click)="openInBrowser('docs.zano.org/docs/how-to-get-alias')">-->
<button [routerLink]="['/assign-alias']" *ngIf="!variablesService.currentWallet.alias.hasOwnProperty('name') && variablesService.currentWallet.loaded && variablesService.daemon_state === 2 && variablesService.currentWallet.alias_available">
<i class="icon account"></i>

View file

@ -27,6 +27,10 @@
h3 {
font-size: 1.7rem;
font-weight: 600;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
max-width: 50rem;
}
button {

View file

@ -15,7 +15,7 @@
"BACK": "Go back"
},
"BREADCRUMBS": {
"ADD_WALLET": "Add new wallet",
"ADD_WALLET": "Add wallet",
"CREATE_WALLET": "Create new wallet",
"SAVE_PHRASE": "Save your seed phrase",
"OPEN_WALLET": "Open existing wallet",
@ -30,7 +30,7 @@
},
"SIDEBAR": {
"TITLE": "Wallets",
"ADD_NEW": "+ Add new",
"ADD_NEW": "+ Add",
"ACCOUNT": {
"STAKING": "Staking",
"MESSAGES": "New offers/Messages",
@ -68,6 +68,7 @@
"FORM_ERRORS": {
"NAME_REQUIRED": "Name is required.",
"NAME_DUPLICATE": "Name is duplicate.",
"MAX_LENGTH": "Maximum name length reached.",
"CONFIRM_NOT_MATCH": "Confirm password not match."
}
},
@ -80,7 +81,8 @@
"FILE_NOT_FOUND2": "<br/><br/> It might have been renamed or moved. <br/> To open it, use the \"Open wallet\" button.",
"FORM_ERRORS": {
"NAME_REQUIRED": "Name is required.",
"NAME_DUPLICATE": "Name is duplicate."
"NAME_DUPLICATE": "Name is duplicate.",
"MAX_LENGTH": "Maximum name length reached."
}
},
"RESTORE_WALLET": {
@ -95,6 +97,7 @@
"FORM_ERRORS": {
"NAME_REQUIRED": "Name is required.",
"NAME_DUPLICATE": "Name is duplicate.",
"MAX_LENGTH": "Maximum name length reached.",
"CONFIRM_NOT_MATCH": "Confirm password not match.",
"KEY_REQUIRED": "Key is required.",
"KEY_NOT_VALID": "Key not valid."
@ -104,11 +107,24 @@
"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 wallet.",
"BUTTON_CREATE_ACCOUNT" : "Create wallet"
},
"PROGRESS": {
"ADD_WALLET": "Add wallet",
"SELECT_LOCATION": "Select wallet location",
"CREATE_WALLET": "Create new wallet",
"RESTORE_WALLET": "Restore from backup"
},
"SETTINGS": {
"TITLE": "Settings",
"DARK_THEME": "Dark theme",
"WHITE_THEME": "White theme",
"GRAY_THEME": "Grey theme",
"APP_LOCK": {
"TITLE": "Lock app after:",
"TIME1": "5 min",
"TIME2": "15 min",
"TIME3": "1 hour",
"TIME4": "Never"
},
"MASTER_PASSWORD": {
"TITLE": "Update master password",
"OLD": "Old password",
@ -145,10 +161,11 @@
"LABEL_SEED_PHRASE": "Seed phrase",
"SEED_PHRASE_HINT": "Click to reveal the seed phrase",
"BUTTON_SAVE": "Save",
"BUTTON_REMOVE": "Remove wallet",
"BUTTON_REMOVE": "Close wallet",
"FORM_ERRORS": {
"NAME_REQUIRED": "Name is required.",
"NAME_DUPLICATE": "Name is duplicate."
"NAME_DUPLICATE": "Name is duplicate.",
"MAX_LENGTH": "Maximum name length reached."
}
},
"ASSIGN_ALIAS": {
@ -170,7 +187,8 @@
"NAME_WRONG": "Alias has wrong name",
"NAME_LENGTH": "The alias must be 6-25 characters long",
"NAME_EXISTS": "Alias name already exists",
"NO_MONEY": "You do not have enough funds to assign this alias"
"NO_MONEY": "You do not have enough funds to assign this alias",
"MAX_LENGTH": "Maximum comment length reached"
},
"ONE_ALIAS": "You can create only one alias per wallet",
"REQUEST_ADD_REG": "The alias will be assigned within 10 minutes"
@ -185,7 +203,8 @@
"PLACEHOLDER": "Enter comment"
},
"FORM_ERRORS": {
"NO_MONEY": "You do not have enough funds to change the comment to this alias"
"NO_MONEY": "You do not have enough funds to change the comment to this alias",
"MAX_LENGTH": "Maximum comment length reached"
},
"COST": "Cost to edit alias {{value}} {{currency}}",
"BUTTON_EDIT": "Edit",
@ -202,7 +221,7 @@
},
"ADDRESS": {
"LABEL": "The account to which the alias will be transferred",
"PLACEHOLDER": "Enter account number"
"PLACEHOLDER": "Enter wallet address"
},
"FORM_ERRORS": {
"WRONG_ADDRESS": "No wallet with this account exists",
@ -234,7 +253,7 @@
},
"HISTORY": {
"STATUS": "Status",
"STATUS_TOOLTIP": "Approved {{current}}/{{total}}",
"STATUS_TOOLTIP": "Confirmations {{current}}/{{total}}",
"SEND": "Send",
"RECEIVED": "Received",
"DATE": "Date",
@ -336,6 +355,7 @@
"AMOUNT": "Amount",
"YOUR_DEPOSIT": "Your deposit",
"SELLER_DEPOSIT": "Seller deposit",
"BUYER_DEPOSIT": "Buyer deposit",
"SAME_AMOUNT": "Same amount",
"COMMENT": "Comment",
"DETAILS": "Additional details",
@ -347,6 +367,7 @@
"SELLER_NOT_VALID": "Seller not valid.",
"AMOUNT_REQUIRED": "Amount is required.",
"YOUR_DEPOSIT_REQUIRED": "Your deposit is required.",
"YOUR_DEPOSIT_TOO_SMALL": "Your deposit should be equal or greater than amount.",
"SELLER_DEPOSIT_REQUIRED": "Seller deposit is required.",
"SELLER_SAME": "The seller's and buyer's accounts are identical. The seller and buyer must use different wallet for the contract.",
"COMMENT_MAXIMUM": "Maximum field length reached."
@ -393,7 +414,13 @@
"BUTTON_RECEIVED": "Item received (Transfer payment and return pledge to seller)",
"BUTTON_CANCEL_BUYER": "Cancel contract (Return pledge)",
"BUTTON_NOT_CANCEL": "Do not cancel (Item shipped)",
"BUTTON_CANCEL_SELLER": "Cancel contract (Return pledge)"
"BUTTON_CANCEL_SELLER": "Cancel contract (Return pledge)",
"HOUR": "hour",
"HOURS": "hours",
"CANCEL": "Cancel",
"NULLIFY_QUESTION": "Are you sure you want to nullify your pledge and the seller's pledge?",
"BUTTON_NULLIFY_SHORT": "Nullify",
"WAITING_TIME_QUESTION": "Are you sure you want to cancel the contract?"
},
"MESSAGES": {
"ADDRESS": "Address",
@ -427,7 +454,7 @@
"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 wallet",
"NOT_ENOUGH_OUTPUTS_TO_MIX": "For the sake of security, mixed transaction will take several days",
"NOT_ENOUGH_OUTPUTS_TO_MIX": "Mix-in number is too big for current blockchain state. There are not enough unspent outputs to mix with",
"TRANSACTION_IS_TO_BIG": "Transaction exceeds network limit, send required amount with multiple transactions",
"TRANSFER_ATTEMPT": "There is no connection to Zano network",
"ACCESS_DENIED": "Access denied",

View file

@ -1,3 +1,16 @@
.app-content {
.preloader {
.loading-bar {
@include themify($themes) {
background-color: themed(progressBarFullBackgroundColor);
}
}
}
}
button {
border: none;
font-family: OpenSans, sans-serif;
@ -24,6 +37,12 @@ button {
&.blue-button:not(:disabled) {
&.error-text {
@include themify($themes) {
color: themed(redTextColor);
}
}
@include themify($themes) {
background-color: themed(blueButtonBackgroundColor);
color: themed(alternativeTextColor);
@ -143,7 +162,7 @@ button {
height: 100%;
min-height: 7.5rem;
max-height: 7.5rem;
overflow: hidden;
overflow: auto;
resize: none;
@include themify($themes) {
@ -165,6 +184,12 @@ button {
}
}
.error-text {
@include themify($themes) {
color: themed(redTextColor);
}
}
input[type='radio'].style-radio {
& + label {
@ -508,6 +533,11 @@ input[type='checkbox'].style-checkbox {
}
}
.account-tooltip {
word-break: break-word;
max-width: 18rem;
}
.ngx-contextmenu {
.dropdown-menu {
@ -546,6 +576,69 @@ input[type='checkbox'].style-checkbox {
}
}
.ng-select {
&.lock-selection-select {
width: 100%;
.ng-select-container {
border: none;
border-radius: 0;
cursor: pointer;
font-size: 1.4rem;
outline: none;
padding: 0 1rem;
height: 4.2rem;
@include themify($themes) {
background-color: themed(inputBackgroundColor);
color: themed(mainTextColor);
}
.ng-value-container {
padding: 0;
}
}
.ng-dropdown-panel {
border: none;
@include themify($themes) {
background-color: themed(inputBackgroundColor);
}
.ng-dropdown-panel-items {
.ng-option {
font-size: 1.4rem;
padding: 1rem;
@include themify($themes) {
background-color: themed(inputBackgroundColor);
color: themed(mainTextColor);
}
&.ng-option-marked {
@include themify($themes) {
background-color: themed(selectHoverColor);
color: themed(mainTextColor);
}
}
&.ng-option-selected {
@include themify($themes) {
background-color: themed(selectSelectedColor);
color: themed(mainTextColor);
}
}
}
}
}
}
}
app-modal-container {
.modal {
@ -635,3 +728,27 @@ app-transaction-details {
}
}
}
app-progress-container {
.progress-bar-container {
@include themify($themes) {
color: themed(mainTextColor);
}
.progress-bar {
@include themify($themes) {
background-color: themed(progressBarBackgroundColor);
}
.progress-bar-full {
@include themify($themes) {
background-color: themed(progressBarFullBackgroundColor);
}
}
}
}
}

View file

@ -22,6 +22,8 @@ $themes: (
turquoiseButtonHoverColor: #52d9ea,
transparentButtonBorderColor: #2b3644,
inputBackgroundColor: #171e27,
selectHoverColor: rgba(58, 72, 90, 0.5),
selectSelectedColor: rgba(43, 54, 68, 0.5),
switchBackgroundColor: #000000,
accountBackgroundColor: rgba(43, 54, 68, 0.5),
accountHoverBackgroundColor: rgba(58, 72, 90, 0.5),
@ -66,6 +68,8 @@ $themes: (
turquoiseButtonHoverColor: #43cee0,
transparentButtonBorderColor: #2f3438,
inputBackgroundColor: #292d31,
selectHoverColor: rgba(70, 76, 81, 0.5),
selectSelectedColor: rgba(37, 40, 43, 0.5),
switchBackgroundColor: #000000,
accountBackgroundColor: rgba(37, 40, 43, 0.5),
accountHoverBackgroundColor: rgba(70, 76, 81, 0.5),
@ -110,6 +114,8 @@ $themes: (
turquoiseButtonHoverColor: #2bbdcf,
transparentButtonBorderColor: #ebebeb,
inputBackgroundColor: #e6e6e6,
selectHoverColor: rgba(240, 240, 240, 0.5),
selectSelectedColor: rgba(224, 224, 224, 0.5),
switchBackgroundColor: #e0e0e0,
accountBackgroundColor: rgba(30, 136, 229, 1),
accountHoverBackgroundColor: rgba(240, 240, 240, 0.5),

View file

@ -75,6 +75,37 @@ app-settings {
color: themed(optionalTextColor);
}
}
.scale-selection {
.button-block {
@include themify($themes) {
background-color: themed(tabInactiveBackgroundColor);
}
.label {
@include themify($themes) {
color: themed(optionalTextColor);
}
}
&.active {
@include themify($themes) {
background-color: themed(blueTextColor);
}
.label {
@include themify($themes) {
color: themed(blueTextColor);
}
}
}
}
}
}
}

View file

@ -138,16 +138,37 @@ app-sidebar {
border-bottom: 0.2rem solid themed(sidebarBorderColor);
}
button {
.wrap-button {
@include themify($themes) {
color: themed(mainTextColor);
}
.icon {
button {
@include themify($themes) {
background-color: themed(blueTextColor);
color: themed(mainTextColor);
}
.icon {
@include themify($themes) {
background-color: themed(blueTextColor);
}
}
}
&.active {
button {
@include themify($themes) {
background-color: themed(accountBackgroundColor)!important;
color: themed(accountMainTextColor)!important;
}
.icon {
@include themify($themes) {
background-color: themed(accountIndicatorBackgroundColor)!important;
}
}
}
}
}

View file

@ -19,6 +19,7 @@
position: relative;
cursor: pointer;
margin-right: 20px;
outline-style: none;
&:after {

View file

@ -15,6 +15,8 @@
@import 'assets/scss/modules/scroll';
@import 'assets/scss/modules/table';
@import "~@ng-select/ng-select/themes/default.theme.css";
@font-face {
font-family: OpenSans;
src: url(~src/assets/fonts/OpenSans-Light.ttf);