Lock/unlock transaction + contact (#86)
* test details & close btn * compiled * confirm modal * delete "cancel" btn from aliases * fix copy btn * text alias fix * confirm pop up * lock & unlock transaction * confirm pop up comment fix * compiled * rebuild html * contact service * rebuild html * fix add contact + rebuild html
|
|
@ -5,6 +5,7 @@
|
|||
"MASTER_PASS": "Master password",
|
||||
"BUTTON_NEXT": "Next",
|
||||
"BUTTON_SKIP": "Skip",
|
||||
"BUTTON_RESET": "Reset",
|
||||
"INCORRECT_PASSWORD": "Invalid password",
|
||||
"FORM_ERRORS": {
|
||||
"PASS_REQUIRED": "Password is required",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
"MASTER_PASS": "Master password",
|
||||
"BUTTON_NEXT": "Next",
|
||||
"BUTTON_SKIP": "Skip",
|
||||
"BUTTON_RESET": "Reset",
|
||||
"INCORRECT_PASSWORD": "Invalid password",
|
||||
"FORM_ERRORS": {
|
||||
"PASS_REQUIRED": "Password is required",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
"MASTER_PASS": "Master password",
|
||||
"BUTTON_NEXT": "Next",
|
||||
"BUTTON_SKIP": "Skip",
|
||||
"BUTTON_RESET": "Reset",
|
||||
"INCORRECT_PASSWORD": "Invalid password",
|
||||
"FORM_ERRORS": {
|
||||
"PASS_REQUIRED": "Password is required",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
"MASTER_PASS": "Master password",
|
||||
"BUTTON_NEXT": "Next",
|
||||
"BUTTON_SKIP": "Skip",
|
||||
"BUTTON_RESET": "Reset",
|
||||
"INCORRECT_PASSWORD": "Invalid password",
|
||||
"FORM_ERRORS": {
|
||||
"PASS_REQUIRED": "Password is required",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
"MASTER_PASS": "Master password",
|
||||
"BUTTON_NEXT": "Next",
|
||||
"BUTTON_SKIP": "Skip",
|
||||
"BUTTON_RESET": "Reset",
|
||||
"INCORRECT_PASSWORD": "Invalid password",
|
||||
"FORM_ERRORS": {
|
||||
"PASS_REQUIRED": "Password is required",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
"MASTER_PASS": "Master password",
|
||||
"BUTTON_NEXT": "Next",
|
||||
"BUTTON_SKIP": "Skip",
|
||||
"BUTTON_RESET": "Reset",
|
||||
"INCORRECT_PASSWORD": "Invalid password",
|
||||
"FORM_ERRORS": {
|
||||
"PASS_REQUIRED": "Password is required",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
"MASTER_PASS": "Master password",
|
||||
"BUTTON_NEXT": "Next",
|
||||
"BUTTON_SKIP": "Skip",
|
||||
"BUTTON_RESET": "Reset",
|
||||
"INCORRECT_PASSWORD": "Invalid password",
|
||||
"FORM_ERRORS": {
|
||||
"PASS_REQUIRED": "Password is required",
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
"MESSAGES": "New offers/Messages",
|
||||
"SYNCING": "Syncing wallet"
|
||||
},
|
||||
"CONTACTS": "Contacts",
|
||||
"SETTINGS": "Settings",
|
||||
"LOG_OUT": "Log out",
|
||||
"SYNCHRONIZATION": {
|
||||
|
|
@ -192,18 +193,17 @@
|
|||
},
|
||||
"ASSIGN_ALIAS": {
|
||||
"NAME": {
|
||||
"LABEL": "Unique name",
|
||||
"LABEL": "Alias",
|
||||
"PLACEHOLDER": "@ Enter alias",
|
||||
"TOOLTIP": "An alias is a shortened form or your account. An alias can only include Latin letters, numbers and characters “.” and “-”. It must start with “@”."
|
||||
},
|
||||
"COMMENT": {
|
||||
"LABEL": "Comment",
|
||||
"PLACEHOLDER": "Enter comment",
|
||||
"PLACEHOLDER": "",
|
||||
"TOOLTIP": "The comment will be visible to anyone who wants to make a payment to your alias. You can provide details about your business, contacts, or include any text. Comments can be edited later."
|
||||
},
|
||||
"COST": "Cost to create alias {{value}} {{currency}}",
|
||||
"COST": "Alias fee {{value}} {{currency}}",
|
||||
"BUTTON_ASSIGN": "Assign",
|
||||
"BUTTON_CANCEL": "Cancel",
|
||||
"FORM_ERRORS": {
|
||||
"NAME_REQUIRED": "Name is required",
|
||||
"NAME_WRONG": "Alias has wrong name",
|
||||
|
|
@ -217,40 +217,39 @@
|
|||
},
|
||||
"EDIT_ALIAS": {
|
||||
"NAME": {
|
||||
"LABEL": "Unique name",
|
||||
"LABEL": "Alias",
|
||||
"PLACEHOLDER": "@ Enter alias"
|
||||
},
|
||||
"COMMENT": {
|
||||
"LABEL": "Comment",
|
||||
"PLACEHOLDER": "Enter comment"
|
||||
"PLACEHOLDER": ""
|
||||
},
|
||||
"FORM_ERRORS": {
|
||||
"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",
|
||||
"BUTTON_CANCEL": "Cancel"
|
||||
"COST": "Fee {{value}} {{currency}}",
|
||||
"BUTTON_EDIT": "Edit"
|
||||
},
|
||||
"TRANSFER_ALIAS": {
|
||||
"NAME": {
|
||||
"LABEL": "Unique name",
|
||||
"LABEL": "Alias",
|
||||
"PLACEHOLDER": "@ Enter alias"
|
||||
},
|
||||
"COMMENT": {
|
||||
"LABEL": "Comment",
|
||||
"PLACEHOLDER": "Enter comment"
|
||||
"PLACEHOLDER": ""
|
||||
},
|
||||
"ADDRESS": {
|
||||
"LABEL": "The account to which the alias will be transferred",
|
||||
"PLACEHOLDER": "Enter wallet address"
|
||||
"LABEL": "Transfer to",
|
||||
"PLACEHOLDER": ""
|
||||
},
|
||||
"FORM_ERRORS": {
|
||||
"WRONG_ADDRESS": "No wallet with this account exists",
|
||||
"ALIAS_EXISTS": "This account already has an alias",
|
||||
"NO_MONEY": "You do not have enough funds to transfer this alias"
|
||||
},
|
||||
"COST": "Cost to transfer alias {{value}} {{currency}}",
|
||||
"COST": "Transfer fee {{value}} {{currency}}",
|
||||
"BUTTON_TRANSFER": "Transfer",
|
||||
"BUTTON_CANCEL": "Cancel",
|
||||
"REQUEST_SEND_REG": "The alias will be transferred within 10 minutes"
|
||||
|
|
@ -453,6 +452,17 @@
|
|||
"INFO": "Information",
|
||||
"OK": "OK"
|
||||
},
|
||||
"CONFIRM": {
|
||||
"BUTTON_CONFIRM": "Send",
|
||||
"BUTTON_CANCEL": "Cancel",
|
||||
"TITLE": "Confirm transaction",
|
||||
"MESSAGE": {
|
||||
"SEND": "Send",
|
||||
"FROM": "From",
|
||||
"TO": "To",
|
||||
"COMMENT": "Comment"
|
||||
}
|
||||
},
|
||||
"STAKING": {
|
||||
"TITLE": "Staking",
|
||||
"TITLE_PENDING": "Pending",
|
||||
|
|
@ -478,6 +488,55 @@
|
|||
"OFF": "OFF"
|
||||
}
|
||||
},
|
||||
"CONTACTS": {
|
||||
"TITLE": "Contact list",
|
||||
"IMPORT_EXPORT": "Import or export contacts",
|
||||
"IMPORT": "Import",
|
||||
"EXPORT": "Export",
|
||||
"ADD": "Add/edit contact",
|
||||
"SEND": "Send",
|
||||
"SEND_FROM": "Send from",
|
||||
"SEND_TO": "To",
|
||||
"OPEN_ADD_WALLET": "Open/Add wallet",
|
||||
"COPY": "- Copy"
|
||||
, "TABLE": {
|
||||
"NAME": "Name",
|
||||
"ALIAS": "Alias",
|
||||
"ADDRESS": "Address",
|
||||
"NOTES": "Notes",
|
||||
"EMPTY": "Contact list is empty"
|
||||
},
|
||||
"FORM": {
|
||||
"NAME": "Name",
|
||||
"ADDRESS": "Address",
|
||||
"NOTES": "Notes"
|
||||
},
|
||||
"FORM_ERRORS": {
|
||||
"NAME_REQUIRED": "Name is required",
|
||||
"NAME_DUBLICATED": "Name is dublicated",
|
||||
"ADDRESS_REQUIRED": "Address is required",
|
||||
"ADDRESS_NOT_VALID": "Address not valid",
|
||||
"SET_MASTER_PASSWORD": "Set master password",
|
||||
"ADDRESS_DUBLICATED": "Address is dublicated",
|
||||
"MAX_LENGTH": "Maximum notes length reached",
|
||||
"NAME_WRONG": "Contact has wrong name",
|
||||
"NAME_LENGTH": "The name must be 4-25 characters long"
|
||||
},
|
||||
"BUTTON": {
|
||||
"SEND": "Send",
|
||||
"EDIT": "Edit",
|
||||
"DELETE": "Delete",
|
||||
"ADD": "Add contact",
|
||||
"ADD_EDIT": "Add/Save",
|
||||
"GO_TO_WALLET": "Go to wallet",
|
||||
"IMPORT_EXPORT": "Import/export"
|
||||
},
|
||||
"SUCCESS_SENT": "Contact added",
|
||||
"SUCCESS_SAVE": "Contact is edited",
|
||||
"SUCCESS_IMPORT": "Contacts is imported",
|
||||
"ERROR_IMPORT": "Error is occured while reading file!",
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file."
|
||||
},
|
||||
"ERRORS": {
|
||||
"NO_MONEY": "Not enough money",
|
||||
"NOT_ENOUGH_MONEY": "Insufficient funds in account",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
"MASTER_PASS": "Master password",
|
||||
"BUTTON_NEXT": "Next",
|
||||
"BUTTON_SKIP": "Skip",
|
||||
"BUTTON_RESET": "Reset",
|
||||
"INCORRECT_PASSWORD": "Invalid password",
|
||||
"FORM_ERRORS": {
|
||||
"PASS_REQUIRED": "Password is required",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
"MASTER_PASS": "Master password",
|
||||
"BUTTON_NEXT": "Next",
|
||||
"BUTTON_SKIP": "Skip",
|
||||
"BUTTON_RESET": "Reset",
|
||||
"INCORRECT_PASSWORD": "Invalid password",
|
||||
"FORM_ERRORS": {
|
||||
"PASS_REQUIRED": "Password is required",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
"MASTER_PASS": "Master password",
|
||||
"BUTTON_NEXT": "Next",
|
||||
"BUTTON_SKIP": "Skip",
|
||||
"BUTTON_RESET": "Reset",
|
||||
"INCORRECT_PASSWORD": "Invalid password",
|
||||
"FORM_ERRORS": {
|
||||
"PASS_REQUIRED": "Password is required",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
"MASTER_PASS": "Master password",
|
||||
"BUTTON_NEXT": "Next",
|
||||
"BUTTON_SKIP": "Skip",
|
||||
"BUTTON_RESET": "Reset",
|
||||
"INCORRECT_PASSWORD": "Invalid password",
|
||||
"FORM_ERRORS": {
|
||||
"PASS_REQUIRED": "Password is required",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
"MASTER_PASS": "Master password",
|
||||
"BUTTON_NEXT": "Next",
|
||||
"BUTTON_SKIP": "Skip",
|
||||
"BUTTON_RESET": "Reset",
|
||||
"INCORRECT_PASSWORD": "Invalid password",
|
||||
"FORM_ERRORS": {
|
||||
"PASS_REQUIRED": "Password is required",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
"MASTER_PASS": "Master password",
|
||||
"BUTTON_NEXT": "Next",
|
||||
"BUTTON_SKIP": "Skip",
|
||||
"BUTTON_RESET": "Reset",
|
||||
"INCORRECT_PASSWORD": "Invalid password",
|
||||
"FORM_ERRORS": {
|
||||
"PASS_REQUIRED": "Password is required",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
"MASTER_PASS": "Master password",
|
||||
"BUTTON_NEXT": "Next",
|
||||
"BUTTON_SKIP": "Skip",
|
||||
"BUTTON_RESET": "Reset",
|
||||
"INCORRECT_PASSWORD": "Invalid password",
|
||||
"FORM_ERRORS": {
|
||||
"PASS_REQUIRED": "Password is required",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
"MASTER_PASS": "Master password",
|
||||
"BUTTON_NEXT": "Next",
|
||||
"BUTTON_SKIP": "Skip",
|
||||
"BUTTON_RESET": "Reset",
|
||||
"INCORRECT_PASSWORD": "Invalid password",
|
||||
"FORM_ERRORS": {
|
||||
"PASS_REQUIRED": "Password is required",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
"MASTER_PASS": "Master password",
|
||||
"BUTTON_NEXT": "Next",
|
||||
"BUTTON_SKIP": "Skip",
|
||||
"BUTTON_RESET": "Reset",
|
||||
"INCORRECT_PASSWORD": "Invalid password",
|
||||
"FORM_ERRORS": {
|
||||
"PASS_REQUIRED": "Password is required",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
"MASTER_PASS": "Master password",
|
||||
"BUTTON_NEXT": "Next",
|
||||
"BUTTON_SKIP": "Skip",
|
||||
"BUTTON_RESET": "Reset",
|
||||
"INCORRECT_PASSWORD": "Invalid password",
|
||||
"FORM_ERRORS": {
|
||||
"PASS_REQUIRED": "Password is required",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
"MASTER_PASS": "Master password",
|
||||
"BUTTON_NEXT": "Next",
|
||||
"BUTTON_SKIP": "Skip",
|
||||
"BUTTON_RESET": "Reset",
|
||||
"INCORRECT_PASSWORD": "Invalid password",
|
||||
"FORM_ERRORS": {
|
||||
"PASS_REQUIRED": "Password is required",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
"MASTER_PASS": "Master password",
|
||||
"BUTTON_NEXT": "Next",
|
||||
"BUTTON_SKIP": "Skip",
|
||||
"BUTTON_RESET": "Reset",
|
||||
"INCORRECT_PASSWORD": "Invalid password",
|
||||
"FORM_ERRORS": {
|
||||
"PASS_REQUIRED": "Password is required",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
"MASTER_PASS": "Master password",
|
||||
"BUTTON_NEXT": "Next",
|
||||
"BUTTON_SKIP": "Skip",
|
||||
"BUTTON_RESET": "Reset",
|
||||
"INCORRECT_PASSWORD": "Invalid password",
|
||||
"FORM_ERRORS": {
|
||||
"PASS_REQUIRED": "Password is required",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
"MASTER_PASS": "Master password",
|
||||
"BUTTON_NEXT": "Next",
|
||||
"BUTTON_SKIP": "Skip",
|
||||
"BUTTON_RESET": "Reset",
|
||||
"INCORRECT_PASSWORD": "Invalid password",
|
||||
"FORM_ERRORS": {
|
||||
"PASS_REQUIRED": "Password is required",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
"MASTER_PASS": "Master password",
|
||||
"BUTTON_NEXT": "Next",
|
||||
"BUTTON_SKIP": "Skip",
|
||||
"BUTTON_RESET": "Reset",
|
||||
"INCORRECT_PASSWORD": "Invalid password",
|
||||
"FORM_ERRORS": {
|
||||
"PASS_REQUIRED": "Password is required",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
"MASTER_PASS": "Master password",
|
||||
"BUTTON_NEXT": "Next",
|
||||
"BUTTON_SKIP": "Skip",
|
||||
"BUTTON_RESET": "Reset",
|
||||
"INCORRECT_PASSWORD": "Invalid password",
|
||||
"FORM_ERRORS": {
|
||||
"PASS_REQUIRED": "Password is required",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
"MASTER_PASS": "Master password",
|
||||
"BUTTON_NEXT": "Next",
|
||||
"BUTTON_SKIP": "Skip",
|
||||
"BUTTON_RESET": "Reset",
|
||||
"INCORRECT_PASSWORD": "Invalid password",
|
||||
"FORM_ERRORS": {
|
||||
"PASS_REQUIRED": "Password is required",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
"MASTER_PASS": "Master password",
|
||||
"BUTTON_NEXT": "Next",
|
||||
"BUTTON_SKIP": "Skip",
|
||||
"BUTTON_RESET": "Reset",
|
||||
"INCORRECT_PASSWORD": "Invalid password",
|
||||
"FORM_ERRORS": {
|
||||
"PASS_REQUIRED": "Password is required",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
"MASTER_PASS": "Master password",
|
||||
"BUTTON_NEXT": "Next",
|
||||
"BUTTON_SKIP": "Skip",
|
||||
"BUTTON_RESET": "Reset",
|
||||
"INCORRECT_PASSWORD": "Invalid password",
|
||||
"FORM_ERRORS": {
|
||||
"PASS_REQUIRED": "Password is required",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
"MASTER_PASS": "Master password",
|
||||
"BUTTON_NEXT": "Next",
|
||||
"BUTTON_SKIP": "Skip",
|
||||
"BUTTON_RESET": "Reset",
|
||||
"INCORRECT_PASSWORD": "Invalid password",
|
||||
"FORM_ERRORS": {
|
||||
"PASS_REQUIRED": "Password is required",
|
||||
|
|
|
|||
19
src/gui/qt-daemon/html/assets/icons/contacts.svg
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<?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 384 384" style="enable-background:new 0 0 384 384;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<title>icons_5</title>
|
||||
<g id="f31d9964-f67b-451c-9eb6-78b833647305">
|
||||
<path class="st0" d="M299.9,197.6c9.3-16.7,14.2-35.5,14.1-54.6c0-70-43.4-105-97-105s-97,35-97,105c-0.1,19.1,4.8,38,14.2,54.6
|
||||
C89.2,218.8,68.5,274.1,50,346l334-0.1C365.5,274,344.8,218.8,299.9,197.6z M178.1,94c11.6-11.6,27.6-14,38.9-14s27.3,2.4,38.9,14
|
||||
c13.3,13.2,16.1,34,16.1,49c0,34.7-24.7,63-55,63s-55-28.3-55-63C162,115.7,170.7,101.3,178.1,94z M128.8,256.5
|
||||
c10.1-14.3,21.1-22.1,36.1-25c31.4,22,73.1,22,104.5-0.1c14.9,2.9,25.9,10.8,35.9,25c8.9,12.6,16.3,29.3,22.7,47.5L106.1,304
|
||||
C112.5,285.8,119.9,269.1,128.8,256.5z"/>
|
||||
<path class="st0" d="M32.5,261H0v42h18.2C23,287,27.6,273.3,32.5,261z"/>
|
||||
<path class="st0" d="M83,182c-0.9-3.6-1.7-7.3-2.4-11H0v42h56.8C64.2,201.6,73,191.2,83,182z"/>
|
||||
<path class="st0" d="M88.8,81H0v42h79C80.4,108.6,83.7,94.5,88.8,81z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
11
src/gui/qt-daemon/html/assets/icons/delete.svg
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?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_2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 384 384" style="enable-background:new 0 0 384 384;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<path class="st0" d="M371,76H269V14H115v62H13v42h35v266h288V118h35V76z M157,56h70v20h-70V56z M294,342H90V118h204V342z"/>
|
||||
<rect x="136" y="166" class="st0" width="42" height="128"/>
|
||||
<rect x="206" y="166" class="st0" width="42" height="128"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 651 B |
10
src/gui/qt-daemon/html/assets/icons/edit.svg
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="icons" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 384 384" style="enable-background:new 0 0 384 384;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<path id="details_1_" class="st0" d="M384,112.9L271.1,0L25,246.1v83.8L0.3,354l29.3,30l25.6-25h82.6L384,112.9z M324.6,112.9
|
||||
l-36.4,36.4l-53.5-53.5l36.4-36.4L324.6,112.9z M70.3,317l-3.3-3.5v-50l138-138l53.5,53.5l-138,138H70.3z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 637 B |
10
src/gui/qt-daemon/html/assets/icons/import-export.svg
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<?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="icons" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 384 384" style="enable-background:new 0 0 384 384;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<polygon class="st0" points="296.5,366 384,288 296.5,210.5 296.5,267 0,267 0,309 296.5,309 "/>
|
||||
<polygon class="st0" points="87.5,18 0,96 87.5,173.5 87.5,117 384,117 384,75 87.5,75 "/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 592 B |
10
src/gui/qt-daemon/html/assets/icons/unlock-transaction.svg
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 23.0.4, 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 32 32" style="enable-background:new 0 0 32 32;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<path class="st0" d="M22,15h-3.4H9.9v-5c0-3.3,2.7-6,6-6H16c3,0,5.4,2.2,5.9,5h4c-0.5-5-4.8-9-9.9-9h-0.1c-5.5,0-10,4.5-10,10v5H3
|
||||
v17h12.9H16h13V15h-3H22z M18,27h-4v-7h4V27z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 581 B |
|
|
@ -997,3 +997,29 @@ app-open-wallet-modal {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
app-send-modal {
|
||||
.modal {
|
||||
|
||||
@include themify($themes) {
|
||||
background: themed(modalBackground);
|
||||
color: themed(mainTextColor);
|
||||
}
|
||||
|
||||
.title {
|
||||
|
||||
@include themify($themes) {
|
||||
border-bottom: 0.2rem solid themed(transparentButtonBorderColor);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.action-button {
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed(blueTextColor);
|
||||
color: themed(alternativeTextColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
88
src/gui/qt-daemon/html/assets/scss/layout/_contact.scss
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
app-contacts, app-add-contacts,
|
||||
app-contact-send, app-export-import {
|
||||
flex: 1 1 auto;
|
||||
padding: 3rem;
|
||||
min-width: 85rem;
|
||||
|
||||
.content {
|
||||
position: relative;
|
||||
padding: 3rem;
|
||||
min-height: 100%;
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed(contentBackgroundColor);
|
||||
color: themed(mainTextColor);
|
||||
}
|
||||
|
||||
.head {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
app-contacts {
|
||||
|
||||
table {
|
||||
|
||||
.alias {
|
||||
|
||||
@include themify($themes) {
|
||||
color: themed(blueTextColor);
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
|
||||
.icon {
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed(blueTextColor);
|
||||
}
|
||||
}
|
||||
|
||||
span {
|
||||
|
||||
@include themify($themes) {
|
||||
color: themed(mainTextColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
|
||||
@include themify($themes) {
|
||||
color: themed(blueTextColor);
|
||||
}
|
||||
|
||||
.import-btn {
|
||||
|
||||
@include themify($themes) {
|
||||
color: themed(blueTextColor);
|
||||
}
|
||||
|
||||
.icon {
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed(blueTextColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
app-contact-send {
|
||||
|
||||
.wallets-selection {
|
||||
|
||||
button {
|
||||
|
||||
@include themify($themes) {
|
||||
color: themed(blueTextColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -199,6 +199,13 @@ app-history {
|
|||
}
|
||||
}
|
||||
|
||||
.unlock-transaction {
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed(blueTextColor);
|
||||
}
|
||||
}
|
||||
|
||||
.status.send {
|
||||
|
||||
.status-transaction {
|
||||
|
|
|
|||
19
src/gui/qt-daemon/html/contacts.svg
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<?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 384 384" style="enable-background:new 0 0 384 384;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<title>icons_5</title>
|
||||
<g id="f31d9964-f67b-451c-9eb6-78b833647305">
|
||||
<path class="st0" d="M299.9,197.6c9.3-16.7,14.2-35.5,14.1-54.6c0-70-43.4-105-97-105s-97,35-97,105c-0.1,19.1,4.8,38,14.2,54.6
|
||||
C89.2,218.8,68.5,274.1,50,346l334-0.1C365.5,274,344.8,218.8,299.9,197.6z M178.1,94c11.6-11.6,27.6-14,38.9-14s27.3,2.4,38.9,14
|
||||
c13.3,13.2,16.1,34,16.1,49c0,34.7-24.7,63-55,63s-55-28.3-55-63C162,115.7,170.7,101.3,178.1,94z M128.8,256.5
|
||||
c10.1-14.3,21.1-22.1,36.1-25c31.4,22,73.1,22,104.5-0.1c14.9,2.9,25.9,10.8,35.9,25c8.9,12.6,16.3,29.3,22.7,47.5L106.1,304
|
||||
C112.5,285.8,119.9,269.1,128.8,256.5z"/>
|
||||
<path class="st0" d="M32.5,261H0v42h18.2C23,287,27.6,273.3,32.5,261z"/>
|
||||
<path class="st0" d="M83,182c-0.9-3.6-1.7-7.3-2.4-11H0v42h56.8C64.2,201.6,73,191.2,83,182z"/>
|
||||
<path class="st0" d="M88.8,81H0v42h79C80.4,108.6,83.7,94.5,88.8,81z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
11
src/gui/qt-daemon/html/delete.svg
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?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_2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 384 384" style="enable-background:new 0 0 384 384;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<path class="st0" d="M371,76H269V14H115v62H13v42h35v266h288V118h35V76z M157,56h70v20h-70V56z M294,342H90V118h204V342z"/>
|
||||
<rect x="136" y="166" class="st0" width="42" height="128"/>
|
||||
<rect x="206" y="166" class="st0" width="42" height="128"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 651 B |
10
src/gui/qt-daemon/html/edit.svg
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="icons" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 384 384" style="enable-background:new 0 0 384 384;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<path id="details_1_" class="st0" d="M384,112.9L271.1,0L25,246.1v83.8L0.3,354l29.3,30l25.6-25h82.6L384,112.9z M324.6,112.9
|
||||
l-36.4,36.4l-53.5-53.5l36.4-36.4L324.6,112.9z M70.3,317l-3.3-3.5v-50l138-138l53.5,53.5l-138,138H70.3z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 637 B |
10
src/gui/qt-daemon/html/import-export.svg
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<?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="icons" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 384 384" style="enable-background:new 0 0 384 384;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<polygon class="st0" points="296.5,366 384,288 296.5,210.5 296.5,267 0,267 0,309 296.5,309 "/>
|
||||
<polygon class="st0" points="87.5,18 0,96 87.5,173.5 87.5,117 384,117 384,75 87.5,75 "/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 592 B |
|
|
@ -5800,8 +5800,8 @@ __webpack_require__.r(__webpack_exports__);
|
|||
/*! no static exports found */
|
||||
/***/ (function(module, exports, __webpack_require__) {
|
||||
|
||||
__webpack_require__(/*! E:\Zano\check\zano\src\gui\qt-daemon\html_source\src\polyfills.ts */"./src/polyfills.ts");
|
||||
module.exports = __webpack_require__(/*! E:\Zano\check\zano\src\gui\qt-daemon\html_source\node_modules\@angular-devkit\build-angular\src\angular-cli-files\models\jit-polyfills.js */"./node_modules/@angular-devkit/build-angular/src/angular-cli-files/models/jit-polyfills.js");
|
||||
__webpack_require__(/*! d:\Projects_now\ZANO\zano\src\gui\qt-daemon\html_source\src\polyfills.ts */"./src/polyfills.ts");
|
||||
module.exports = __webpack_require__(/*! d:\Projects_now\ZANO\zano\src\gui\qt-daemon\html_source\node_modules\@angular-devkit\build-angular\src\angular-cli-files\models\jit-polyfills.js */"./node_modules/@angular-devkit/build-angular/src/angular-cli-files/models/jit-polyfills.js");
|
||||
|
||||
|
||||
/***/ })
|
||||
|
|
|
|||
10
src/gui/qt-daemon/html/unlock-transaction.svg
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 23.0.4, 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 32 32" style="enable-background:new 0 0 32 32;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<path class="st0" d="M22,15h-3.4H9.9v-5c0-3.3,2.7-6,6-6H16c3,0,5.4,2.2,5.9,5h4c-0.5-5-4.8-9-9.9-9h-0.1c-5.5,0-10,4.5-10,10v5H3
|
||||
v17h12.9H16h13V15h-3H22z M18,27h-4v-7h4V27z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 581 B |
|
|
@ -33,6 +33,7 @@
|
|||
"idlejs": "^2.0.1",
|
||||
"json-bignumber": "^1.0.1",
|
||||
"ngx-contextmenu": "^5.1.1",
|
||||
"ngx-papaparse": "^3.0.3",
|
||||
"qrcode": "^1.3.0",
|
||||
"rxjs": "~6.3.3",
|
||||
"zone.js": "~0.8.26"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
export class Contact {
|
||||
name: string;
|
||||
address: string;
|
||||
alias?;
|
||||
notes: string;
|
||||
}
|
||||
|
|
@ -313,11 +313,17 @@ export class BackendService {
|
|||
this.runCommand('check_master_password', pass, callback);
|
||||
}
|
||||
storeSecureAppData(callback?) {
|
||||
let data;
|
||||
const wallets = [];
|
||||
const contacts = [];
|
||||
this.variablesService.wallets.forEach((wallet) => {
|
||||
wallets.push({name: wallet.name, pass: wallet.pass, path: wallet.path, staking: wallet.staking});
|
||||
});
|
||||
this.backendObject['store_secure_app_data'](JSON.stringify(wallets), this.variablesService.appPass, (dataStore) => {
|
||||
this.variablesService.contacts.forEach((contact) => {
|
||||
contacts.push({name: contact.name, address: contact.address, notes: contact.notes});
|
||||
});
|
||||
data = {wallets: wallets, contacts: contacts};
|
||||
this.backendObject['store_secure_app_data'](JSON.stringify(data), this.variablesService.appPass, (dataStore) => {
|
||||
this.backendCallback(dataStore, {}, callback, 'store_secure_app_data');
|
||||
});
|
||||
}
|
||||
|
|
@ -352,6 +358,14 @@ export class BackendService {
|
|||
this.runCommand('show_openfile_dialog', params, callback);
|
||||
}
|
||||
|
||||
storeFile(path, buff) {
|
||||
this.backendObject['store_to_file'](path, (typeof buff === 'string' ? buff : JSON.stringify(buff)));
|
||||
}
|
||||
|
||||
loadFile(path, callback) {
|
||||
this.runCommand('load_from_file', path, callback);
|
||||
}
|
||||
|
||||
generateWallet(path, pass, callback) {
|
||||
const params = {
|
||||
path: path,
|
||||
|
|
@ -601,6 +615,22 @@ export class BackendService {
|
|||
return {};
|
||||
}
|
||||
|
||||
getContactAlias() {
|
||||
if (this.variablesService.contacts.length && this.variablesService.daemon_state === 2) {
|
||||
this.variablesService.contacts.map(contact => {
|
||||
this.getAliasByAddress(contact.address, (status, data) => {
|
||||
if (status) {
|
||||
if (data.alias) {
|
||||
contact.alias = '@' + data.alias;
|
||||
}
|
||||
} else {
|
||||
contact.alias = null;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
getPoolInfo(callback) {
|
||||
this.runCommand('get_tx_pool_info', {}, callback);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import {Injectable, NgZone} from '@angular/core';
|
||||
import {Wallet} from '../models/wallet.model';
|
||||
import {Contact} from '../models/contact.model';
|
||||
import {BehaviorSubject} from 'rxjs';
|
||||
import {Idle} from 'idlejs/dist';
|
||||
import {Router} from '@angular/router';
|
||||
|
|
@ -45,12 +46,16 @@ export class VariablesService {
|
|||
|
||||
public wallets: Array<Wallet> = [];
|
||||
public currentWallet: Wallet;
|
||||
public selectWallet: number;
|
||||
public aliases: any = [];
|
||||
public aliasesChecked: any = {};
|
||||
public enableAliasSearch = false;
|
||||
public maxWalletNameLength = 25;
|
||||
public maxCommentLength = 255;
|
||||
public dataIsLoaded = false;
|
||||
public dataIsLoaded = false;
|
||||
|
||||
public contacts: Array<Contact> = [];
|
||||
public newContact: Contact = {name: null, address: null, notes: null};
|
||||
|
||||
getExpMedTsEvent = new BehaviorSubject(null);
|
||||
getHeightAppEvent = new BehaviorSubject(null);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,69 @@
|
|||
<div class="content scrolled-content">
|
||||
<div class="head">
|
||||
<div class="breadcrumbs">
|
||||
<span [routerLink]="['/contacts']">{{ 'CONTACTS.TITLE' | translate }}</span>
|
||||
<span>{{ 'CONTACTS.ADD' | translate }}</span>
|
||||
</div>
|
||||
<button type="button" class="back-btn" (click)="back()">
|
||||
<i class="icon back"></i>
|
||||
<span>{{ 'COMMON.BACK' | translate }}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<form class="form-add" [formGroup]="addContactForm" (ngSubmit)="add()">
|
||||
|
||||
<div class="input-block input-block-name">
|
||||
<label for="add-name">{{ 'CONTACTS.FORM.NAME' | translate }}</label>
|
||||
<input type="text" id="add-name" formControlName="name" (contextmenu)="variablesService.onContextMenu($event)">
|
||||
<div class="error-block" *ngIf="addContactForm.controls['name'].invalid && (addContactForm.controls['name'].dirty || addContactForm.controls['name'].touched)">
|
||||
<div *ngIf="addContactForm.controls['name'].errors['pattern']">
|
||||
{{ 'CONTACTS.FORM_ERRORS.NAME_WRONG' | translate }}
|
||||
</div>
|
||||
<div *ngIf="addContactForm.get('name').value.length < 4 || addContactForm.get('name').value.length > 25">
|
||||
{{ 'CONTACTS.FORM_ERRORS.NAME_LENGTH' | translate }}
|
||||
</div>
|
||||
<div *ngIf="addContactForm.controls['name'].errors['required']">
|
||||
{{ 'CONTACTS.FORM_ERRORS.NAME_REQUIRED' | translate }}
|
||||
</div>
|
||||
<div *ngIf="addContactForm.controls['name'].errors['dublicated']">
|
||||
{{ 'CONTACTS.FORM_ERRORS.NAME_DUBLICATED' | translate }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="input-block input-block-alias">
|
||||
<label for="address">{{ 'CONTACTS.FORM.ADDRESS' | translate }}</label>
|
||||
|
||||
<input type="text" id="address" formControlName="address" (contextmenu)="variablesService.onContextMenu($event)">
|
||||
|
||||
<div class="error-block" *ngIf="addContactForm.controls['address'].invalid && (addContactForm.controls['address'].dirty || addContactForm.controls['address'].touched)">
|
||||
<div *ngIf="addContactForm.controls['address'].errors['required']">
|
||||
{{ 'CONTACTS.FORM_ERRORS.ADDRESS_REQUIRED' | translate }}
|
||||
</div>
|
||||
<div *ngIf="addContactForm.controls['address'].errors['address_not_valid']">
|
||||
{{ 'CONTACTS.FORM_ERRORS.ADDRESS_NOT_VALID' | translate }}
|
||||
</div>
|
||||
<div *ngIf="addContactForm.controls['address'].errors['dublicated']">
|
||||
{{ 'CONTACTS.FORM_ERRORS.ADDRESS_DUBLICATED' | translate }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="input-block input-block-notes">
|
||||
<label for="notes">{{ 'CONTACTS.FORM.NOTES' | translate }}</label>
|
||||
|
||||
<input type="text" id="notes" formControlName="notes" (contextmenu)="variablesService.onContextMenu($event)">
|
||||
|
||||
<div class="error-block" *ngIf="addContactForm.controls['notes'].invalid">
|
||||
<div *ngIf="addContactForm.controls['notes'].errors['maxLength']">
|
||||
{{ 'CONTACTS.FORM_ERRORS.MAX_LENGTH' | translate }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="blue-button" [disabled]="!addContactForm.valid">{{ 'CONTACTS.BUTTON.ADD_EDIT' | translate }}</button>
|
||||
|
||||
<app-send-modal *ngIf="isModalDialogVisible" [form]="addContactForm" (confirmed)="confirmed($event)"></app-send-modal>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
.form-add {
|
||||
margin-top: 3rem;
|
||||
|
||||
.input-block-name {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
button {
|
||||
margin-top: 3rem;
|
||||
width: 100%;
|
||||
max-width: 18rem;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { AddContactsComponent } from './add-contacts.component';
|
||||
|
||||
describe('AddContactsComponent', () => {
|
||||
let component: AddContactsComponent;
|
||||
let fixture: ComponentFixture<AddContactsComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ AddContactsComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(AddContactsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,189 @@
|
|||
import { Component, OnInit, NgZone, OnDestroy } 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 { Location } from '@angular/common';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'app-add-contacts',
|
||||
templateUrl: './add-contacts.component.html',
|
||||
styleUrls: ['./add-contacts.component.scss']
|
||||
})
|
||||
export class AddContactsComponent implements OnInit, OnDestroy {
|
||||
id: number;
|
||||
queryRouting;
|
||||
addContactForm = new FormGroup({
|
||||
address: new FormControl('', [
|
||||
Validators.required,
|
||||
(g: FormControl) => {
|
||||
if (g.value) {
|
||||
this.backend.validateAddress(g.value, valid_status => {
|
||||
this.ngZone.run(() => {
|
||||
if (valid_status === false) {
|
||||
g.setErrors(
|
||||
Object.assign({ address_not_valid: true }, g.errors)
|
||||
);
|
||||
} else {
|
||||
if (g.hasError('address_not_valid')) {
|
||||
delete g.errors['address_not_valid'];
|
||||
if (Object.keys(g.errors).length === 0) {
|
||||
g.setErrors(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
return g.hasError('address_not_valid')
|
||||
? { address_not_valid: true }
|
||||
: null;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
(g: FormControl) => {
|
||||
const isDublicated = this.variablesService.contacts.findIndex(
|
||||
contact => contact.address === g.value
|
||||
);
|
||||
if (isDublicated !== -1 && !(this.id === isDublicated)) {
|
||||
return { dublicated: true };
|
||||
}
|
||||
return null;
|
||||
}
|
||||
]),
|
||||
notes: new FormControl('', [
|
||||
(g: FormControl) => {
|
||||
if (g.value) {
|
||||
if (g.value.length > this.variablesService.maxCommentLength) {
|
||||
return { maxLength: true };
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
]),
|
||||
name: new FormControl('', [
|
||||
Validators.required,
|
||||
Validators.pattern(/^[\w\s-_.]{4,25}$/),
|
||||
(g: FormControl) => {
|
||||
if (g.value) {
|
||||
const isDublicated = this.variablesService.contacts.findIndex(
|
||||
contact => contact.name === g.value.trim()
|
||||
);
|
||||
if (isDublicated !== -1 && !(this.id === isDublicated)) {
|
||||
return { dublicated: true };
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
])
|
||||
});
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private backend: BackendService,
|
||||
public variablesService: VariablesService,
|
||||
private modalService: ModalService,
|
||||
private ngZone: NgZone,
|
||||
private location: Location
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.queryRouting = this.route.queryParams.subscribe(params => {
|
||||
if (params.id) {
|
||||
this.id = parseInt(params.id, 10);
|
||||
this.addContactForm.reset({
|
||||
name: this.variablesService.contacts[params.id]['name'],
|
||||
address: this.variablesService.contacts[params.id]['address'],
|
||||
notes: this.variablesService.contacts[params.id]['notes']
|
||||
});
|
||||
} else {
|
||||
this.addContactForm.reset({
|
||||
name: this.variablesService.newContact['name'],
|
||||
address: this.variablesService.newContact['address'],
|
||||
notes: this.variablesService.newContact['notes']
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
add() {
|
||||
if (!this.variablesService.appPass) {
|
||||
this.modalService.prepareModal(
|
||||
'error',
|
||||
'CONTACTS.FORM_ERRORS.SET_MASTER_PASSWORD'
|
||||
);
|
||||
} else {
|
||||
if (this.addContactForm.valid) {
|
||||
this.backend.validateAddress(
|
||||
this.addContactForm.get('address').value,
|
||||
valid_status => {
|
||||
if (valid_status === false) {
|
||||
this.ngZone.run(() => {
|
||||
this.addContactForm
|
||||
.get('address')
|
||||
.setErrors({ address_not_valid: true });
|
||||
});
|
||||
} else {
|
||||
if (this.id || this.id === 0) {
|
||||
this.variablesService.contacts.forEach((contact, index) => {
|
||||
if (index === this.id) {
|
||||
contact.name = this.addContactForm.get('name').value.trim();
|
||||
contact.address = this.addContactForm.get('address').value;
|
||||
contact.notes =
|
||||
this.addContactForm.get('notes').value || '';
|
||||
}
|
||||
});
|
||||
this.backend.storeSecureAppData();
|
||||
this.backend.getContactAlias();
|
||||
this.modalService.prepareModal(
|
||||
'success',
|
||||
'CONTACTS.SUCCESS_SAVE'
|
||||
);
|
||||
} else {
|
||||
this.variablesService.contacts.push({
|
||||
name: this.addContactForm.get('name').value.trim(),
|
||||
address: this.addContactForm.get('address').value,
|
||||
notes: this.addContactForm.get('notes').value || ''
|
||||
});
|
||||
this.backend.storeSecureAppData();
|
||||
this.backend.getContactAlias();
|
||||
this.modalService.prepareModal(
|
||||
'success',
|
||||
'CONTACTS.SUCCESS_SENT'
|
||||
);
|
||||
this.variablesService.newContact = {
|
||||
name: null,
|
||||
address: null,
|
||||
notes: null
|
||||
};
|
||||
this.addContactForm.reset({
|
||||
name: null,
|
||||
address: null,
|
||||
notes: null
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
back() {
|
||||
this.location.back();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
if (!(this.id || this.id === 0)) {
|
||||
this.variablesService.newContact = {
|
||||
name: this.addContactForm.get('name').value,
|
||||
address: this.addContactForm.get('address').value,
|
||||
notes: this.addContactForm.get('notes').value
|
||||
};
|
||||
}
|
||||
this.queryRouting.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
|
@ -20,8 +20,12 @@ import { RestoreWalletComponent } from './restore-wallet/restore-wallet.componen
|
|||
import { SeedPhraseComponent } from './seed-phrase/seed-phrase.component';
|
||||
import { WalletDetailsComponent } from './wallet-details/wallet-details.component';
|
||||
import { AssignAliasComponent } from './assign-alias/assign-alias.component';
|
||||
import { EditAliasComponent } from "./edit-alias/edit-alias.component";
|
||||
import { TransferAliasComponent } from "./transfer-alias/transfer-alias.component";
|
||||
import { EditAliasComponent } from './edit-alias/edit-alias.component';
|
||||
import { TransferAliasComponent } from './transfer-alias/transfer-alias.component';
|
||||
import { ContactsComponent } from './contacts/contacts.component';
|
||||
import { AddContactsComponent } from './add-contacts/add-contacts.component';
|
||||
import { ContactSendComponent } from './contact-send/contact-send.component';
|
||||
import { ExportImportComponent } from './export-import/export-import.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
|
|
@ -119,6 +123,26 @@ const routes: Routes = [
|
|||
path: 'settings',
|
||||
component: SettingsComponent
|
||||
},
|
||||
{
|
||||
path: 'contacts',
|
||||
component: ContactsComponent
|
||||
},
|
||||
{
|
||||
path: 'add-contacts',
|
||||
component: AddContactsComponent
|
||||
},
|
||||
{
|
||||
path: 'edit-contacts/:id',
|
||||
component: AddContactsComponent
|
||||
},
|
||||
{
|
||||
path: 'contact-send/:id',
|
||||
component: ContactSendComponent
|
||||
},
|
||||
{
|
||||
path: 'import',
|
||||
component: ExportImportComponent
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
redirectTo: '/',
|
||||
|
|
|
|||
|
|
@ -193,6 +193,7 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||
});
|
||||
if (!this.firstOnlineState && data['daemon_network_state'] === 2) {
|
||||
this.getAliases();
|
||||
this.backend.getContactAlias();
|
||||
this.backend.getDefaultFee((status_fee, data_fee) => {
|
||||
this.variablesService.default_fee_big = new BigNumber(data_fee);
|
||||
this.variablesService.default_fee = this.intToMoneyPipe.transform(data_fee);
|
||||
|
|
|
|||
|
|
@ -51,12 +51,17 @@ import * as highcharts from 'highcharts';
|
|||
import exporting from 'highcharts/modules/exporting.src';
|
||||
import { ProgressContainerComponent } from './_helpers/directives/progress-container/progress-container.component';
|
||||
import { InputDisableSelectionDirective } from './_helpers/directives/input-disable-selection/input-disable-selection.directive';
|
||||
import { SendModalComponent } from './send-modal/send-modal.component';
|
||||
import { ContactsComponent } from './contacts/contacts.component';
|
||||
import { AddContactsComponent } from './add-contacts/add-contacts.component';
|
||||
import { ContactSendComponent } from './contact-send/contact-send.component';
|
||||
import { ExportImportComponent } from './export-import/export-import.component';
|
||||
|
||||
export function HttpLoaderFactory(httpClient: HttpClient) {
|
||||
return new TranslateHttpLoader(httpClient, './assets/i18n/', '.json');
|
||||
}
|
||||
|
||||
|
||||
import { PapaParseModule } from 'ngx-papaparse';
|
||||
// import * as more from 'highcharts/highcharts-more.src';
|
||||
// import * as exporting from 'highcharts/modules/exporting.src';
|
||||
// import * as highstock from 'highcharts/modules/stock.src';
|
||||
|
|
@ -108,7 +113,12 @@ export function highchartsFactory() {
|
|||
ModalContainerComponent,
|
||||
TransactionDetailsComponent,
|
||||
ProgressContainerComponent,
|
||||
InputDisableSelectionDirective
|
||||
InputDisableSelectionDirective,
|
||||
SendModalComponent,
|
||||
ContactsComponent,
|
||||
AddContactsComponent,
|
||||
ContactSendComponent,
|
||||
ExportImportComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
|
|
@ -125,6 +135,7 @@ export function highchartsFactory() {
|
|||
ReactiveFormsModule,
|
||||
NgSelectModule,
|
||||
ChartModule,
|
||||
PapaParseModule,
|
||||
ContextMenuModule.forRoot()
|
||||
],
|
||||
providers: [
|
||||
|
|
@ -136,7 +147,8 @@ export function highchartsFactory() {
|
|||
// {provide: HIGHCHARTS_MODULES, useFactory: () => [ highstock, more, exporting ] }
|
||||
],
|
||||
entryComponents: [
|
||||
ModalContainerComponent
|
||||
ModalContainerComponent,
|
||||
SendModalComponent
|
||||
],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
|
|
|
|||
|
|
@ -61,7 +61,6 @@
|
|||
|
||||
<div class="wrap-buttons">
|
||||
<button type="button" class="blue-button" (click)="assignAlias()" [disabled]="!assignForm.valid || !canRegister || notEnoughMoney">{{ 'ASSIGN_ALIAS.BUTTON_ASSIGN' | translate }}</button>
|
||||
<button type="button" class="blue-button" (click)="back()">{{ 'ASSIGN_ALIAS.BUTTON_CANCEL' | translate }}</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
<div class="content scrolled-content">
|
||||
<div class="head">
|
||||
<div class="breadcrumbs">
|
||||
<span [routerLink]="['/contacts']">{{
|
||||
'CONTACTS.TITLE' | translate
|
||||
}}</span>
|
||||
<span>{{ 'CONTACTS.SEND' | translate }}</span>
|
||||
</div>
|
||||
<button type="button" class="back-btn" (click)="back()">
|
||||
<i class="icon back"></i>
|
||||
<span>{{ 'COMMON.BACK' | translate }}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="wallets-selection">
|
||||
<div class="input-block">
|
||||
<label>
|
||||
{{ 'CONTACTS.SEND_FROM' | translate }}
|
||||
</label>
|
||||
<ng-select
|
||||
class="custom-select"
|
||||
[items]="this.variablesService.wallets"
|
||||
[(ngModel)]="this.variablesService.selectWallet"
|
||||
bindValue="wallet_id"
|
||||
bindLabel="name"
|
||||
[clearable]="false"
|
||||
[searchable]="false"
|
||||
>
|
||||
</ng-select>
|
||||
</div>
|
||||
<button [routerLink]="['/main']">
|
||||
{{ 'CONTACTS.OPEN_ADD_WALLET' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="input-block">
|
||||
<label for="address">{{ 'CONTACTS.SEND_TO' | translate }}</label>
|
||||
<input type="text" id="address" [ngModel]="address" [readonly]="true"/>
|
||||
</div>
|
||||
</div>
|
||||
<button class="blue-button" [routerLink]="['/wallet/' + this.variablesService.selectWallet + '/send']" [queryParams]="{send: true}" (click)="goToWallet(this.variablesService.selectWallet)"
|
||||
[disabled]="!(this.variablesService.selectWallet === 0 || this.variablesService.selectWallet)">{{ 'CONTACTS.BUTTON.GO_TO_WALLET' | translate }}</button>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
.wallets-selection {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 2rem;
|
||||
|
||||
.input-block {
|
||||
width: 18rem;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 2rem;
|
||||
background: transparent;
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
.input-block {
|
||||
width: 44rem;
|
||||
|
||||
input {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
.blue-button {
|
||||
margin-top: 2.5rem;
|
||||
width: 100%;
|
||||
max-width: 18rem;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ContactSendComponent } from './contact-send.component';
|
||||
|
||||
describe('ContactSendComponent', () => {
|
||||
let component: ContactSendComponent;
|
||||
let fixture: ComponentFixture<ContactSendComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ ContactSendComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ContactSendComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||
import { Location } from '@angular/common';
|
||||
import { VariablesService } from '../_helpers/services/variables.service';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-contact-send',
|
||||
templateUrl: './contact-send.component.html',
|
||||
styleUrls: ['./contact-send.component.scss']
|
||||
})
|
||||
export class ContactSendComponent implements OnInit, OnDestroy {
|
||||
|
||||
queryRouting;
|
||||
address;
|
||||
|
||||
constructor(
|
||||
private location: Location,
|
||||
private variablesService: VariablesService,
|
||||
private route: ActivatedRoute
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.queryRouting = this.route.queryParams.subscribe(params => {
|
||||
if (params.address) {
|
||||
this.address = params.address;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
goToWallet(id) {
|
||||
this.variablesService.setCurrentWallet(id);
|
||||
this.variablesService.currentWallet.send_data['address'] = this.address;
|
||||
}
|
||||
|
||||
back() {
|
||||
this.location.back();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.queryRouting.unsubscribe();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
<div class="content scrolled-content">
|
||||
<div>
|
||||
<div class="head">
|
||||
<button type="button" class="back-btn" (click)="back()">
|
||||
<i class="icon back"></i>
|
||||
<span>{{ 'COMMON.BACK' | translate }}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<h3 class="contacts-title">{{ 'CONTACTS.TITLE' | translate }}</h3>
|
||||
|
||||
<div class="wrap-table">
|
||||
<ng-container>
|
||||
<table
|
||||
*ngIf="this.variablesService.contacts.length !== 0; else emptyList"
|
||||
>
|
||||
<thead>
|
||||
<tr #head (window:resize)="calculateWidth()">
|
||||
<th>{{ 'CONTACTS.TABLE.NAME' | translate }}</th>
|
||||
<th>{{ 'CONTACTS.TABLE.ALIAS' | translate }}</th>
|
||||
<th>{{ 'CONTACTS.TABLE.ADDRESS' | translate }}</th>
|
||||
<th>{{ 'CONTACTS.TABLE.NOTES' | translate }}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<ng-container
|
||||
*ngFor="
|
||||
let contact of this.variablesService.contacts;
|
||||
let i = index
|
||||
"
|
||||
>
|
||||
<tr>
|
||||
<td>
|
||||
{{ contact.name }}
|
||||
</td>
|
||||
<td>
|
||||
<ng-container *ngIf="contact.alias">
|
||||
<span
|
||||
class="alias"
|
||||
(click)="openInBrowser(contact.alias)"
|
||||
>{{ contact.alias }}</span
|
||||
>
|
||||
</ng-container>
|
||||
</td>
|
||||
<td class="remote-address">
|
||||
{{ contact.address }}
|
||||
</td>
|
||||
<td class="remote-notes">
|
||||
{{ contact.notes }}
|
||||
</td>
|
||||
<td>
|
||||
<div class="button-wrapper">
|
||||
<button
|
||||
[routerLink]="['/contact-send/' + i]"
|
||||
[queryParams]="{ address: contact.address }"
|
||||
>
|
||||
<i class="icon transfer"></i>
|
||||
<span>{{ 'CONTACTS.BUTTON.SEND' | translate }}</span>
|
||||
</button>
|
||||
<button
|
||||
[routerLink]="['/edit-contacts/' + i]"
|
||||
[queryParams]="{ id: i }"
|
||||
>
|
||||
<i class="icon edit"></i>
|
||||
<span>{{ 'CONTACTS.BUTTON.EDIT' | translate }}</span>
|
||||
</button>
|
||||
<button (click)="delete(i)">
|
||||
<i class="icon delete"></i>
|
||||
<span>{{ 'CONTACTS.BUTTON.DELETE' | translate }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</ng-container>
|
||||
</tbody>
|
||||
</table>
|
||||
</ng-container>
|
||||
|
||||
<ng-template #emptyList>
|
||||
<div class="empty-list">
|
||||
{{ 'CONTACTS.TABLE.EMPTY' | translate }}
|
||||
</div>
|
||||
</ng-template>
|
||||
</div>
|
||||
|
||||
<button [routerLink]="['/add-contacts']" class="blue-button">
|
||||
{{ 'CONTACTS.BUTTON.ADD' | translate }}
|
||||
</button>
|
||||
|
||||
<div class="footer">
|
||||
<button type="button" class="import-btn" [routerLink]="['/import']">
|
||||
<i class="icon import"></i>
|
||||
<span>{{ 'CONTACTS.BUTTON.IMPORT_EXPORT' | translate }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
:host {
|
||||
min-width: 95rem;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.head {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.contacts-title {
|
||||
font-size: 1.7rem;
|
||||
}
|
||||
|
||||
.wrap-table {
|
||||
margin: 1rem -3rem;
|
||||
|
||||
table {
|
||||
|
||||
tbody{
|
||||
|
||||
tr {
|
||||
|
||||
td {
|
||||
padding: 0 3rem 0 1rem;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
&:first-child {
|
||||
max-width: 10rem;
|
||||
padding: 0 3rem 0 3rem;
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
max-width: 10rem;
|
||||
}
|
||||
|
||||
.alias {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.button-wrapper {
|
||||
display: flex;
|
||||
|
||||
button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: transparent;
|
||||
border: none;
|
||||
font-size: 1.3rem;
|
||||
font-weight: 400;
|
||||
line-height: 3rem;
|
||||
outline: none;
|
||||
padding: 0;
|
||||
height: auto;
|
||||
margin-right: 1.8rem;
|
||||
|
||||
.icon {
|
||||
cursor: pointer;
|
||||
margin-right: 0.8rem;
|
||||
width: 1.7rem;
|
||||
height: 1.7rem;
|
||||
|
||||
&.edit {
|
||||
mask: url(../../assets/icons/edit.svg) no-repeat center;
|
||||
}
|
||||
|
||||
&.transfer {
|
||||
mask: url(../../assets/icons/send.svg) no-repeat center;
|
||||
}
|
||||
|
||||
&.delete {
|
||||
mask: url(../../assets/icons/delete.svg) no-repeat center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.empty-list {
|
||||
margin: 2.5rem 3rem;
|
||||
}
|
||||
}
|
||||
|
||||
.blue-button {
|
||||
width: 100%;
|
||||
max-width: 18rem;
|
||||
margin-top: 3rem;
|
||||
}
|
||||
|
||||
|
||||
.footer {
|
||||
position: absolute;
|
||||
bottom: 3rem;
|
||||
font-size: 1.3rem;
|
||||
|
||||
.import-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: transparent;
|
||||
font-size: inherit;
|
||||
font-weight: 400;
|
||||
line-height: 1.3rem;
|
||||
padding: 0;
|
||||
height: auto;
|
||||
|
||||
.icon {
|
||||
margin-right: 0.7rem;
|
||||
mask: url(../../assets/icons/import-export.svg) no-repeat center;
|
||||
width: 0.9rem;
|
||||
height: 0.9rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ContactsComponent } from './contacts.component';
|
||||
|
||||
describe('ContactsComponent', () => {
|
||||
let component: ContactsComponent;
|
||||
let fixture: ComponentFixture<ContactsComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ ContactsComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ContactsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';
|
||||
import { Location } from '@angular/common';
|
||||
import { VariablesService } from '../_helpers/services/variables.service';
|
||||
import { BackendService } from '../_helpers/services/backend.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-contacts',
|
||||
templateUrl: './contacts.component.html',
|
||||
styleUrls: ['./contacts.component.scss']
|
||||
})
|
||||
export class ContactsComponent implements OnInit {
|
||||
calculatedWidth = [];
|
||||
@ViewChild('head') head: ElementRef;
|
||||
|
||||
constructor(
|
||||
private location: Location,
|
||||
private variablesService: VariablesService,
|
||||
private backend: BackendService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.backend.getContactAlias();
|
||||
}
|
||||
|
||||
delete(index: number) {
|
||||
if (this.variablesService.appPass) {
|
||||
this.variablesService.contacts.splice(index, 1);
|
||||
this.backend.storeSecureAppData();
|
||||
}
|
||||
}
|
||||
|
||||
calculateWidth() {
|
||||
this.calculatedWidth = [];
|
||||
this.calculatedWidth.push(
|
||||
this.head.nativeElement.childNodes[0].clientWidth
|
||||
);
|
||||
this.calculatedWidth.push(
|
||||
this.head.nativeElement.childNodes[1].clientWidth +
|
||||
this.head.nativeElement.childNodes[2].clientWidth
|
||||
);
|
||||
this.calculatedWidth.push(
|
||||
this.head.nativeElement.childNodes[3].clientWidth
|
||||
);
|
||||
this.calculatedWidth.push(
|
||||
this.head.nativeElement.childNodes[4].clientWidth
|
||||
);
|
||||
}
|
||||
|
||||
openInBrowser(alias: string) {
|
||||
if (alias !== null) {
|
||||
this.backend.openUrlInBrowser(
|
||||
`explorer.zano.org/aliases/${alias.slice(1)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
back() {
|
||||
this.location.back();
|
||||
}
|
||||
}
|
||||
|
|
@ -44,7 +44,6 @@
|
|||
|
||||
<div class="wrap-buttons">
|
||||
<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>
|
||||
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
<div class="content scrolled-content">
|
||||
<div>
|
||||
<div class="head">
|
||||
<button type="button" class="back-btn" (click)="back()">
|
||||
<i class="icon back"></i>
|
||||
<span>{{ 'COMMON.BACK' | translate }}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<h3 class="contacts-title">{{ 'CONTACTS.IMPORT_EXPORT' | translate }}</h3>
|
||||
|
||||
<div class="btn-wrapper">
|
||||
<button class="blue-button" type="button" (click)="import()">
|
||||
{{ 'CONTACTS.IMPORT' | translate }}
|
||||
</button>
|
||||
<button class="blue-button" type="button" (click)="export()">
|
||||
{{ 'CONTACTS.EXPORT' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
:host {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.head {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.contacts-title {
|
||||
font-size: 1.7rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.btn-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin: 0 -0.5rem;
|
||||
padding: 1.5rem 0;
|
||||
|
||||
button {
|
||||
flex: 1 0 auto;
|
||||
margin: 0 0.5rem;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ExportImportComponent } from './export-import.component';
|
||||
|
||||
describe('ExportImportComponent', () => {
|
||||
let component: ExportImportComponent;
|
||||
let fixture: ComponentFixture<ExportImportComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ ExportImportComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ExportImportComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { Location } from '@angular/common';
|
||||
import { BackendService } from '../_helpers/services/backend.service';
|
||||
import { VariablesService } from '../_helpers/services/variables.service';
|
||||
import { Contact } from '../_helpers/models/contact.model';
|
||||
import { ModalService } from '../_helpers/services/modal.service';
|
||||
import { Papa } from 'ngx-papaparse';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-export-import',
|
||||
templateUrl: './export-import.component.html',
|
||||
styleUrls: ['./export-import.component.scss']
|
||||
})
|
||||
export class ExportImportComponent implements OnInit {
|
||||
csvContent;
|
||||
|
||||
constructor(
|
||||
private location: Location,
|
||||
private variablesService: VariablesService,
|
||||
private backend: BackendService,
|
||||
private modalService: ModalService,
|
||||
private papa: Papa,
|
||||
private translate: TranslateService
|
||||
) {}
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
import() {
|
||||
this.backend.openFileDialog(
|
||||
'',
|
||||
'*',
|
||||
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('/')
|
||||
);
|
||||
if (this.isValid(file_data.path)) {
|
||||
this.backend.loadFile(file_data.path, (status, data) => {
|
||||
if (status) {
|
||||
const options = {
|
||||
header: true
|
||||
};
|
||||
const elements = this.papa.parse(data, options);
|
||||
|
||||
if (elements.data && !elements.errors.length) {
|
||||
if (!this.variablesService.contacts.length) {
|
||||
elements.data.forEach(element => {
|
||||
this.variablesService.contacts.push(element);
|
||||
});
|
||||
} else {
|
||||
elements.data.forEach(element => {
|
||||
const indexName = this.variablesService.contacts.findIndex(
|
||||
contact => contact.name === element.name
|
||||
);
|
||||
const indexAddress = this.variablesService.contacts.findIndex(
|
||||
contact => contact.address === element.address
|
||||
);
|
||||
if (indexAddress === -1 && indexName === -1) {
|
||||
this.variablesService.contacts.push(element);
|
||||
}
|
||||
if (indexName !== -1 && indexAddress === -1) {
|
||||
this.variablesService.contacts.push({
|
||||
name: `${element.name} ${this.translate.instant(
|
||||
'CONTACTS.COPY'
|
||||
)}`,
|
||||
address: element.address,
|
||||
notes: element.notes
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
this.backend.getContactAlias();
|
||||
this.modalService.prepareModal(
|
||||
'success',
|
||||
'CONTACTS.SUCCESS_IMPORT'
|
||||
);
|
||||
}
|
||||
if (elements.errors.length) {
|
||||
this.modalService.prepareModal(
|
||||
'error',
|
||||
'CONTACTS.ERROR_IMPORT'
|
||||
);
|
||||
console.log(elements.errors);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.modalService.prepareModal('error', 'CONTACTS.ERROR_TYPE_FILE');
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export() {
|
||||
const contacts: Array<Contact> = [];
|
||||
this.variablesService.contacts.forEach(contact => {
|
||||
delete contact.alias;
|
||||
contacts.push(contact);
|
||||
});
|
||||
|
||||
this.backend.saveFileDialog(
|
||||
'',
|
||||
'*',
|
||||
this.variablesService.settings.default_path,
|
||||
(file_status, file_data) => {
|
||||
if (file_status) {
|
||||
this.backend.storeFile(file_data.path, this.papa.unparse(contacts));
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
isValid(file) {
|
||||
return file.endsWith('.csv');
|
||||
}
|
||||
|
||||
back() {
|
||||
this.location.back();
|
||||
}
|
||||
}
|
||||
|
|
@ -13,16 +13,33 @@
|
|||
<tbody>
|
||||
<ng-container *ngFor="let item of variablesService.currentWallet.history">
|
||||
<tr (click)="openDetails(item.tx_hash)" [class.locked-transaction]="!item.is_mining && item.unlock_time > 0">
|
||||
<td>
|
||||
<td>
|
||||
<div class="status" [class.send]="!item.is_income" [class.received]="item.is_income">
|
||||
<ng-container *ngIf="variablesService.height_app - item.height < 10 || item.height === 0 && item.timestamp > 0">
|
||||
<div class="confirmation" tooltip="{{ 'HISTORY.STATUS_TOOLTIP' | translate : {'current': getHeight(item)/10, 'total': 10} }}" placement="bottom-left" tooltipClass="table-tooltip" [delay]="500">
|
||||
<div class="fill" [style.height]="getHeight(item) + '%'"></div>
|
||||
</div>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!item.is_mining && item.unlock_time > 0">
|
||||
<i class="icon lock-transaction" tooltip="{{ 'HISTORY.LOCK_TOOLTIP' | translate : {'date': item.unlock_time * 1000 | date : 'MM.dd.yy'} }}" placement="bottom-left" tooltipClass="table-tooltip" [delay]="500"></i>
|
||||
|
||||
<ng-container *ngIf="item.unlock_time !== 0 && item.tx_type !== 6">
|
||||
<ng-container *ngIf="isLocked(item); else unlock">
|
||||
<ng-container *ngIf="item.unlock_time < 500000000">
|
||||
<i class="icon lock-transaction" tooltip="{{ 'HISTORY.LOCK_TOOLTIP' | translate : {'date': time(item) | date : 'MM.dd.yy'} }}" placement="bottom-left" tooltipClass="table-tooltip" [delay]="500"
|
||||
[class.position]="variablesService.height_app - item.height < 10 || item.height === 0 && item.timestamp > 0"></i>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="item.unlock_time > 500000000">
|
||||
<i class="icon lock-transaction" tooltip="{{ 'HISTORY.LOCK_TOOLTIP' | translate : {'date': item.unlock_time * 1000 | date : 'MM.dd.yy'} }}" placement="bottom-left" tooltipClass="table-tooltip" [delay]="500"
|
||||
[class.position]="variablesService.height_app - item.height < 10 || item.height === 0 && item.timestamp > 0"></i>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
<ng-template #unlock>
|
||||
<i class="icon unlock-transaction" placement="bottom-left" [class.position]="variablesService.height_app - item.height < 10 || item.height === 0 && item.timestamp > 0"></i>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
|
||||
<!-- <ng-container *ngIf="!item.is_mining && item.unlock_time > 0">
|
||||
<i class="icon lock-transaction" tooltip="{{ 'HISTORY.LOCK_TOOLTIP' | translate : {'date': item.unlock_time * 1000 | date : 'MM.dd.yy'} }}" placement="bottom-left" tooltipClass="table-tooltip" [delay]="500"></i>
|
||||
</ng-container> -->
|
||||
<i class="icon status-transaction"></i>
|
||||
<span>{{ (item.is_income ? 'HISTORY.RECEIVED' : 'HISTORY.SEND') | translate }}</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -37,12 +37,24 @@
|
|||
|
||||
.lock-transaction {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: -2rem;
|
||||
transform: translateY(-50%);
|
||||
mask: url(../../assets/icons/lock-transaction.svg) no-repeat center;
|
||||
width: 1.2rem;
|
||||
height: 1.2rem;
|
||||
margin-right: 1.1rem;
|
||||
}
|
||||
|
||||
.unlock-transaction {
|
||||
position: absolute;
|
||||
left: -2rem;
|
||||
mask: url(../../assets/icons/unlock-transaction.svg) no-repeat center;
|
||||
width: 1.2rem;
|
||||
height: 1.2rem;
|
||||
margin-right: 1.1rem;
|
||||
}
|
||||
|
||||
.position {
|
||||
position: static;
|
||||
}
|
||||
|
||||
.status-transaction {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import {Component, OnInit, OnDestroy, AfterViewChecked, ViewChild, ElementRef} from '@angular/core';
|
||||
import {VariablesService} from '../_helpers/services/variables.service';
|
||||
import {ActivatedRoute} from '@angular/router';
|
||||
import { Transaction } from '../_helpers/models/transaction.model';
|
||||
|
||||
@Component({
|
||||
selector: 'app-history',
|
||||
|
|
@ -56,6 +57,23 @@ export class HistoryComponent implements OnInit, OnDestroy, AfterViewChecked {
|
|||
this.calculatedWidth.push(this.head.nativeElement.childNodes[4].clientWidth);
|
||||
}
|
||||
|
||||
time(item: Transaction) {
|
||||
const now = new Date().getTime();
|
||||
const unlockTime = now + ((item.unlock_time - this.variablesService.height_app) * 60 * 1000);
|
||||
return unlockTime;
|
||||
}
|
||||
|
||||
isLocked(item: Transaction) {
|
||||
if ((item.unlock_time > 500000000) && (item.unlock_time > new Date().getTime() / 1000)) {
|
||||
console.log(new Date().getTime());
|
||||
return true;
|
||||
}
|
||||
if ((item.unlock_time < 500000000) && (item.unlock_time > this.variablesService.height_app)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.parentRouting.unsubscribe();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ export class LoginComponent implements OnInit, OnDestroy {
|
|||
password: new FormControl('')
|
||||
});
|
||||
|
||||
type = 'reg';
|
||||
type = 'reg';
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
|
|
@ -61,8 +61,7 @@ export class LoginComponent implements OnInit, OnDestroy {
|
|||
} else {
|
||||
console.log(data['error_code']);
|
||||
}
|
||||
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -74,10 +73,12 @@ export class LoginComponent implements OnInit, OnDestroy {
|
|||
});
|
||||
}
|
||||
|
||||
dropSecureAppData(): void{
|
||||
dropSecureAppData(): void {
|
||||
this.backend.dropSecureAppData(() => {
|
||||
this.onSkipCreatePass();
|
||||
});
|
||||
this.onSkipCreatePass();
|
||||
});
|
||||
this.variablesService.wallets = [];
|
||||
this.variablesService.contacts = [];
|
||||
}
|
||||
|
||||
onSubmitAuthPass(): void {
|
||||
|
|
@ -93,9 +94,9 @@ export class LoginComponent implements OnInit, OnDestroy {
|
|||
this.router.navigate(['/']);
|
||||
});
|
||||
}
|
||||
})
|
||||
});
|
||||
} else {
|
||||
this.getWalletData(this.variablesService.appPass)
|
||||
this.getWalletData(this.variablesService.appPass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -107,16 +108,21 @@ export class LoginComponent implements OnInit, OnDestroy {
|
|||
this.variablesService.dataIsLoaded = true;
|
||||
this.variablesService.startCountdown();
|
||||
this.variablesService.appPass = appPass;
|
||||
if (Object.keys(data['contacts']).length !== 0) {
|
||||
data['contacts'].map(contact => {
|
||||
this.variablesService.contacts.push(contact);
|
||||
});
|
||||
}
|
||||
if (this.variablesService.wallets.length) {
|
||||
this.ngZone.run(() => {
|
||||
this.router.navigate(['/wallet/' + this.variablesService.wallets[0].wallet_id]);
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (Object.keys(data).length !== 0) {
|
||||
if (Object.keys(data['wallets']).length !== 0) {
|
||||
let openWallets = 0;
|
||||
let runWallets = 0;
|
||||
data.forEach((wallet, wallet_index) => {
|
||||
data['wallets'].forEach((wallet, wallet_index) => {
|
||||
this.backend.openWallet(wallet.path, wallet.pass, true, (open_status, open_data, open_error) => {
|
||||
if (open_status || open_error === 'FILE_RESTORED') {
|
||||
openWallets++;
|
||||
|
|
|
|||
|
|
@ -21,8 +21,7 @@
|
|||
|
||||
<div class="wrap-buttons">
|
||||
<button type="button" class="blue-button seed-phrase-button" (click)="runWallet()">{{ 'SEED_PHRASE.BUTTON_CREATE_ACCOUNT' | translate }}</button>
|
||||
<button type="button" class="blue-button copy-button" *ngIf="!seedPhraseCopied" (click)="copySeedPhrase()">{{ 'SEED_PHRASE.BUTTON_COPY' | translate }}</button>
|
||||
<button type="button" class="transparent-button copy-button" *ngIf="seedPhraseCopied" disabled><i class="icon"></i>{{ 'SEED_PHRASE.BUTTON_COPY' | translate }}</button>
|
||||
<button type="button" class="blue-button copy-button" (click)="copySeedPhrase()">{{ 'SEED_PHRASE.BUTTON_COPY' | translate }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
<div class="modal">
|
||||
<div class="title">
|
||||
<span>{{ 'CONFIRM.TITLE' | translate }}</span>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="message-container">
|
||||
<div class="message-block">
|
||||
<div class="message-label">{{ 'CONFIRM.MESSAGE.SEND' | translate }}</div>
|
||||
<div class="message-text">{{ form.get('amount').value }} {{variablesService.defaultCurrency}}</div>
|
||||
</div>
|
||||
<div class="message-block">
|
||||
<div class="message-label">{{ 'CONFIRM.MESSAGE.FROM' | translate }}</div>
|
||||
<div class="message-text">{{ variablesService.currentWallet.address }}</div>
|
||||
</div>
|
||||
<div class="message-block">
|
||||
<div class="message-label">{{ 'CONFIRM.MESSAGE.TO' | translate }}</div>
|
||||
<div class="message-text">{{ form.get('address').value }}</div>
|
||||
</div>
|
||||
<ng-container *ngIf="form.get('comment').value != ''">
|
||||
<div class="message-block" *ngIf="form.get('comment').value != null">
|
||||
<div class="message-label">{{ 'CONFIRM.MESSAGE.COMMENT' | translate }}</div>
|
||||
<div class="message-text">{{ form.get('comment').value }}</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wrapper-buttons">
|
||||
<button type="button" class="blue-button" (click)="confirm()">{{ 'CONFIRM.BUTTON_CONFIRM' | translate }}</button>
|
||||
<button type="button" class="blue-button" (click)="onClose()">{{ 'CONFIRM.BUTTON_CANCEL' | translate }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
:host {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
}
|
||||
.modal {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-position: center;
|
||||
background-size: 200%;
|
||||
padding: 0.3rem 3rem 3rem 3rem;
|
||||
width: 64rem;
|
||||
|
||||
.title {
|
||||
padding: 1.4rem 0;
|
||||
font-size: 1.8rem;
|
||||
line-height: 3rem;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
font-size: 1.4rem;
|
||||
|
||||
.message-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
margin: 1.4rem 3rem 6.2rem 0;
|
||||
|
||||
.message-block {
|
||||
display: flex;
|
||||
margin-bottom: 1rem;
|
||||
|
||||
&:first-child {
|
||||
|
||||
.message-label {
|
||||
line-height: 4rem;
|
||||
}
|
||||
|
||||
.message-text {
|
||||
line-height: 4rem;
|
||||
}
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.message-label {
|
||||
min-width: 6.7rem;
|
||||
line-height: 2rem;
|
||||
}
|
||||
|
||||
.message-text {
|
||||
overflow-wrap: break-word;
|
||||
margin-left: 4.8rem;
|
||||
width: 43.4rem;
|
||||
line-height: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.wrapper-buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
button {
|
||||
width: 100%;
|
||||
max-width: 15rem;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { SendModalComponent } from './send-modal.component';
|
||||
|
||||
describe('SendModalComponent', () => {
|
||||
let component: SendModalComponent;
|
||||
let fixture: ComponentFixture<SendModalComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ SendModalComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SendModalComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
import { Component, OnInit, Output, EventEmitter, Input } from '@angular/core';
|
||||
import { FormGroup } from '@angular/forms';
|
||||
import { VariablesService } from '../_helpers/services/variables.service';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-send-modal',
|
||||
templateUrl: './send-modal.component.html',
|
||||
styleUrls: ['./send-modal.component.scss']
|
||||
})
|
||||
export class SendModalComponent implements OnInit {
|
||||
|
||||
@Input() form: FormGroup;
|
||||
@Output() confirmed: EventEmitter<boolean> = new EventEmitter<boolean>();
|
||||
|
||||
constructor(
|
||||
public variablesService: VariablesService
|
||||
) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
confirm() {
|
||||
this.confirmed.emit(true);
|
||||
}
|
||||
|
||||
onClose() {
|
||||
this.confirmed.emit(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
<form class="form-send" [formGroup]="sendForm" (ngSubmit)="onSend()">
|
||||
<form class="form-send" [formGroup]="sendForm" (ngSubmit)="showDialog()">
|
||||
|
||||
<div class="input-block input-block-alias">
|
||||
<label for="send-address">{{ 'SEND.ADDRESS' | translate }}</label>
|
||||
|
|
@ -85,4 +85,6 @@
|
|||
|
||||
<button type="submit" class="blue-button" [disabled]="!sendForm.valid || !variablesService.currentWallet.loaded">{{ 'SEND.BUTTON' | translate }}</button>
|
||||
|
||||
<app-send-modal *ngIf="isModalDialogVisible" [form]="sendForm" (confirmed)="confirmed($event)"></app-send-modal>
|
||||
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import {Component, OnInit, OnDestroy, NgZone, HostListener} from '@angular/core';
|
||||
import {Component, OnInit, OnDestroy, NgZone, HostListener, Input} from '@angular/core';
|
||||
import {FormGroup, FormControl, Validators} from '@angular/forms';
|
||||
import {ActivatedRoute} from '@angular/router';
|
||||
import {BackendService} from '../_helpers/services/backend.service';
|
||||
|
|
@ -15,6 +15,7 @@ export class SendComponent implements OnInit, OnDestroy {
|
|||
|
||||
isOpen = false;
|
||||
localAliases = [];
|
||||
isModalDialogVisible = false;
|
||||
|
||||
currentWalletId = null;
|
||||
parentRouting;
|
||||
|
|
@ -73,13 +74,7 @@ export class SendComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
return null;
|
||||
}]),
|
||||
comment: new FormControl('', [(g: FormControl) => {
|
||||
if (g.value > this.variablesService.maxCommentLength) {
|
||||
return {'maxLength': true};
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}]),
|
||||
comment: new FormControl(''),
|
||||
mixin: new FormControl(0, Validators.required),
|
||||
fee: new FormControl(this.variablesService.default_fee, [Validators.required, (g: FormControl) => {
|
||||
if ((new BigNumber(g.value)).isLessThan(this.variablesService.default_fee)) {
|
||||
|
|
@ -132,6 +127,17 @@ export class SendComponent implements OnInit, OnDestroy {
|
|||
});
|
||||
}
|
||||
|
||||
showDialog() {
|
||||
this.isModalDialogVisible = true;
|
||||
}
|
||||
|
||||
confirmed(confirmed: boolean) {
|
||||
if (confirmed) {
|
||||
this.onSend();
|
||||
}
|
||||
this.isModalDialogVisible = false;
|
||||
}
|
||||
|
||||
onSend() {
|
||||
if (this.sendForm.valid) {
|
||||
if (this.sendForm.get('address').value.indexOf('@') !== 0) {
|
||||
|
|
|
|||
|
|
@ -38,6 +38,12 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="sidebar-settings">
|
||||
<div class="wrap-button" routerLinkActive="active">
|
||||
<button (click)="contactsRoute()" [class.disabled]="variablesService.daemon_state !== 2" [disabled]="variablesService.daemon_state !== 2">
|
||||
<i class="icon contacts"></i>
|
||||
<span>{{ 'SIDEBAR.CONTACTS' | translate }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="wrap-button" routerLinkActive="active">
|
||||
<button [routerLink]="['/settings']">
|
||||
<i class="icon settings"></i>
|
||||
|
|
|
|||
|
|
@ -198,11 +198,19 @@
|
|||
padding: 0 3rem;
|
||||
width: 100%;
|
||||
|
||||
&.disabled {
|
||||
cursor: url(../../assets/icons/not-allowed.svg), not-allowed;
|
||||
}
|
||||
|
||||
.icon {
|
||||
margin-right: 1.2rem;
|
||||
width: 1.7rem;
|
||||
height: 1.7rem;
|
||||
|
||||
&.contacts {
|
||||
mask: url(../../assets/icons/contacts.svg) no-repeat center;
|
||||
}
|
||||
|
||||
&.settings {
|
||||
mask: url(../../assets/icons/settings.svg) no-repeat center;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import {Component, NgZone, OnInit, OnDestroy} from '@angular/core';
|
|||
import {ActivatedRoute, NavigationStart, Router} from '@angular/router';
|
||||
import {VariablesService} from '../_helpers/services/variables.service';
|
||||
import {BackendService} from '../_helpers/services/backend.service';
|
||||
import { ModalService } from '../_helpers/services/modal.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-sidebar',
|
||||
|
|
@ -18,6 +19,7 @@ export class SidebarComponent implements OnInit, OnDestroy {
|
|||
private router: Router,
|
||||
public variablesService: VariablesService,
|
||||
private backend: BackendService,
|
||||
private modal: ModalService,
|
||||
private ngZone: NgZone
|
||||
) {}
|
||||
|
||||
|
|
@ -49,6 +51,17 @@ export class SidebarComponent implements OnInit, OnDestroy {
|
|||
});
|
||||
}
|
||||
|
||||
contactsRoute() {
|
||||
if (this.variablesService.appPass) {
|
||||
this.router.navigate(['/contacts']);
|
||||
} else {
|
||||
this.modal.prepareModal(
|
||||
'error',
|
||||
'CONTACTS.FORM_ERRORS.SET_MASTER_PASSWORD'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
getUpdate() {
|
||||
this.backend.openUrlInBrowser('zano.org/downloads.html');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,14 +15,14 @@
|
|||
|
||||
<div class="input-block alias-name">
|
||||
<label for="alias-name">
|
||||
{{ 'EDIT_ALIAS.NAME.LABEL' | translate }}
|
||||
{{ 'TRANSFER_ALIAS.NAME.LABEL' | translate }}
|
||||
</label>
|
||||
<input type="text" id="alias-name" [value]="alias.name" placeholder="{{ 'EDIT_ALIAS.NAME.PLACEHOLDER' | translate }}" readonly>
|
||||
</div>
|
||||
|
||||
<div class="input-block textarea">
|
||||
<label for="alias-comment">
|
||||
{{ 'EDIT_ALIAS.COMMENT.LABEL' | translate }}
|
||||
{{ 'TRANSFER_ALIAS.COMMENT.LABEL' | translate }}
|
||||
</label>
|
||||
<textarea id="alias-comment" [value]="alias.comment" placeholder="{{ 'EDIT_ALIAS.COMMENT.PLACEHOLDER' | translate }}" readonly></textarea>
|
||||
</div>
|
||||
|
|
@ -49,7 +49,6 @@
|
|||
|
||||
<div class="wrap-buttons">
|
||||
<button type="button" class="blue-button" (click)="transferAlias()" [disabled]="transferAddressAlias || !transferAddressValid || notEnoughMoney">{{ 'TRANSFER_ALIAS.BUTTON_TRANSFER' | translate }}</button>
|
||||
<button type="button" class="blue-button" (click)="back()">{{ 'TRANSFER_ALIAS.BUTTON_CANCEL' | translate }}</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import {Subscription} from 'rxjs';
|
|||
export class WalletComponent implements OnInit, OnDestroy {
|
||||
subRouting1;
|
||||
subRouting2;
|
||||
queryRouting;
|
||||
walletID;
|
||||
copyAnimation = false;
|
||||
copyAnimationTimeout;
|
||||
|
|
@ -94,6 +95,15 @@ export class WalletComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
}
|
||||
});
|
||||
this.queryRouting = this.route.queryParams.subscribe(params => {
|
||||
if (params.send) {
|
||||
this.tabs.forEach((tab, index) => {
|
||||
if (tab.link === '/send') {
|
||||
this.changeTab(index);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
if (this.variablesService.currentWallet.alias.hasOwnProperty('name')) {
|
||||
this.variablesService.currentWallet.wakeAlias = false;
|
||||
}
|
||||
|
|
@ -178,6 +188,7 @@ export class WalletComponent implements OnInit, OnDestroy {
|
|||
ngOnDestroy() {
|
||||
this.subRouting1.unsubscribe();
|
||||
this.subRouting2.unsubscribe();
|
||||
this.queryRouting.unsubscribe();
|
||||
this.aliasSubscription.unsubscribe();
|
||||
clearTimeout(this.copyAnimationTimeout);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
"MESSAGES": "New offers/Messages",
|
||||
"SYNCING": "Syncing wallet"
|
||||
},
|
||||
"CONTACTS": "Contacts",
|
||||
"SETTINGS": "Settings",
|
||||
"LOG_OUT": "Log out",
|
||||
"SYNCHRONIZATION": {
|
||||
|
|
@ -192,18 +193,17 @@
|
|||
},
|
||||
"ASSIGN_ALIAS": {
|
||||
"NAME": {
|
||||
"LABEL": "Unique name",
|
||||
"LABEL": "Alias",
|
||||
"PLACEHOLDER": "@ Enter alias",
|
||||
"TOOLTIP": "An alias is a shortened form or your account. An alias can only include Latin letters, numbers and characters “.” and “-”. It must start with “@”."
|
||||
},
|
||||
"COMMENT": {
|
||||
"LABEL": "Comment",
|
||||
"PLACEHOLDER": "Enter comment",
|
||||
"PLACEHOLDER": "",
|
||||
"TOOLTIP": "The comment will be visible to anyone who wants to make a payment to your alias. You can provide details about your business, contacts, or include any text. Comments can be edited later."
|
||||
},
|
||||
"COST": "Cost to create alias {{value}} {{currency}}",
|
||||
"COST": "Alias fee {{value}} {{currency}}",
|
||||
"BUTTON_ASSIGN": "Assign",
|
||||
"BUTTON_CANCEL": "Cancel",
|
||||
"FORM_ERRORS": {
|
||||
"NAME_REQUIRED": "Name is required",
|
||||
"NAME_WRONG": "Alias has wrong name",
|
||||
|
|
@ -217,40 +217,39 @@
|
|||
},
|
||||
"EDIT_ALIAS": {
|
||||
"NAME": {
|
||||
"LABEL": "Unique name",
|
||||
"LABEL": "Alias",
|
||||
"PLACEHOLDER": "@ Enter alias"
|
||||
},
|
||||
"COMMENT": {
|
||||
"LABEL": "Comment",
|
||||
"PLACEHOLDER": "Enter comment"
|
||||
"PLACEHOLDER": ""
|
||||
},
|
||||
"FORM_ERRORS": {
|
||||
"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",
|
||||
"BUTTON_CANCEL": "Cancel"
|
||||
"COST": "Fee {{value}} {{currency}}",
|
||||
"BUTTON_EDIT": "Edit"
|
||||
},
|
||||
"TRANSFER_ALIAS": {
|
||||
"NAME": {
|
||||
"LABEL": "Unique name",
|
||||
"LABEL": "Alias",
|
||||
"PLACEHOLDER": "@ Enter alias"
|
||||
},
|
||||
"COMMENT": {
|
||||
"LABEL": "Comment",
|
||||
"PLACEHOLDER": "Enter comment"
|
||||
"PLACEHOLDER": ""
|
||||
},
|
||||
"ADDRESS": {
|
||||
"LABEL": "The account to which the alias will be transferred",
|
||||
"PLACEHOLDER": "Enter wallet address"
|
||||
"LABEL": "Transfer to",
|
||||
"PLACEHOLDER": ""
|
||||
},
|
||||
"FORM_ERRORS": {
|
||||
"WRONG_ADDRESS": "No wallet with this account exists",
|
||||
"ALIAS_EXISTS": "This account already has an alias",
|
||||
"NO_MONEY": "You do not have enough funds to transfer this alias"
|
||||
},
|
||||
"COST": "Cost to transfer alias {{value}} {{currency}}",
|
||||
"COST": "Transfer fee {{value}} {{currency}}",
|
||||
"BUTTON_TRANSFER": "Transfer",
|
||||
"BUTTON_CANCEL": "Cancel",
|
||||
"REQUEST_SEND_REG": "The alias will be transferred within 10 minutes"
|
||||
|
|
@ -453,6 +452,17 @@
|
|||
"INFO": "Information",
|
||||
"OK": "OK"
|
||||
},
|
||||
"CONFIRM": {
|
||||
"BUTTON_CONFIRM": "Send",
|
||||
"BUTTON_CANCEL": "Cancel",
|
||||
"TITLE": "Confirm transaction",
|
||||
"MESSAGE": {
|
||||
"SEND": "Send",
|
||||
"FROM": "From",
|
||||
"TO": "To",
|
||||
"COMMENT": "Comment"
|
||||
}
|
||||
},
|
||||
"STAKING": {
|
||||
"TITLE": "Staking",
|
||||
"TITLE_PENDING": "Pending",
|
||||
|
|
@ -478,6 +488,55 @@
|
|||
"OFF": "OFF"
|
||||
}
|
||||
},
|
||||
"CONTACTS": {
|
||||
"TITLE": "Contact list",
|
||||
"IMPORT_EXPORT": "Import or export contacts",
|
||||
"IMPORT": "Import",
|
||||
"EXPORT": "Export",
|
||||
"ADD": "Add/edit contact",
|
||||
"SEND": "Send",
|
||||
"SEND_FROM": "Send from",
|
||||
"SEND_TO": "To",
|
||||
"OPEN_ADD_WALLET": "Open/Add wallet",
|
||||
"COPY": "- Copy"
|
||||
, "TABLE": {
|
||||
"NAME": "Name",
|
||||
"ALIAS": "Alias",
|
||||
"ADDRESS": "Address",
|
||||
"NOTES": "Notes",
|
||||
"EMPTY": "Contact list is empty"
|
||||
},
|
||||
"FORM": {
|
||||
"NAME": "Name",
|
||||
"ADDRESS": "Address",
|
||||
"NOTES": "Notes"
|
||||
},
|
||||
"FORM_ERRORS": {
|
||||
"NAME_REQUIRED": "Name is required",
|
||||
"NAME_DUBLICATED": "Name is dublicated",
|
||||
"ADDRESS_REQUIRED": "Address is required",
|
||||
"ADDRESS_NOT_VALID": "Address not valid",
|
||||
"SET_MASTER_PASSWORD": "Set master password",
|
||||
"ADDRESS_DUBLICATED": "Address is dublicated",
|
||||
"MAX_LENGTH": "Maximum notes length reached",
|
||||
"NAME_WRONG": "Contact has wrong name",
|
||||
"NAME_LENGTH": "The name must be 4-25 characters long"
|
||||
},
|
||||
"BUTTON": {
|
||||
"SEND": "Send",
|
||||
"EDIT": "Edit",
|
||||
"DELETE": "Delete",
|
||||
"ADD": "Add contact",
|
||||
"ADD_EDIT": "Add/Save",
|
||||
"GO_TO_WALLET": "Go to wallet",
|
||||
"IMPORT_EXPORT": "Import/export"
|
||||
},
|
||||
"SUCCESS_SENT": "Contact added",
|
||||
"SUCCESS_SAVE": "Contact is edited",
|
||||
"SUCCESS_IMPORT": "Contacts is imported",
|
||||
"ERROR_IMPORT": "Error is occured while reading file!",
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file."
|
||||
},
|
||||
"ERRORS": {
|
||||
"NO_MONEY": "Not enough money",
|
||||
"NOT_ENOUGH_MONEY": "Insufficient funds in account",
|
||||
|
|
|
|||
19
src/gui/qt-daemon/html_source/src/assets/icons/contacts.svg
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<?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 384 384" style="enable-background:new 0 0 384 384;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<title>icons_5</title>
|
||||
<g id="f31d9964-f67b-451c-9eb6-78b833647305">
|
||||
<path class="st0" d="M299.9,197.6c9.3-16.7,14.2-35.5,14.1-54.6c0-70-43.4-105-97-105s-97,35-97,105c-0.1,19.1,4.8,38,14.2,54.6
|
||||
C89.2,218.8,68.5,274.1,50,346l334-0.1C365.5,274,344.8,218.8,299.9,197.6z M178.1,94c11.6-11.6,27.6-14,38.9-14s27.3,2.4,38.9,14
|
||||
c13.3,13.2,16.1,34,16.1,49c0,34.7-24.7,63-55,63s-55-28.3-55-63C162,115.7,170.7,101.3,178.1,94z M128.8,256.5
|
||||
c10.1-14.3,21.1-22.1,36.1-25c31.4,22,73.1,22,104.5-0.1c14.9,2.9,25.9,10.8,35.9,25c8.9,12.6,16.3,29.3,22.7,47.5L106.1,304
|
||||
C112.5,285.8,119.9,269.1,128.8,256.5z"/>
|
||||
<path class="st0" d="M32.5,261H0v42h18.2C23,287,27.6,273.3,32.5,261z"/>
|
||||
<path class="st0" d="M83,182c-0.9-3.6-1.7-7.3-2.4-11H0v42h56.8C64.2,201.6,73,191.2,83,182z"/>
|
||||
<path class="st0" d="M88.8,81H0v42h79C80.4,108.6,83.7,94.5,88.8,81z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
11
src/gui/qt-daemon/html_source/src/assets/icons/delete.svg
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?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_2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 384 384" style="enable-background:new 0 0 384 384;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<path class="st0" d="M371,76H269V14H115v62H13v42h35v266h288V118h35V76z M157,56h70v20h-70V56z M294,342H90V118h204V342z"/>
|
||||
<rect x="136" y="166" class="st0" width="42" height="128"/>
|
||||
<rect x="206" y="166" class="st0" width="42" height="128"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 651 B |
10
src/gui/qt-daemon/html_source/src/assets/icons/edit.svg
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="icons" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 384 384" style="enable-background:new 0 0 384 384;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<path id="details_1_" class="st0" d="M384,112.9L271.1,0L25,246.1v83.8L0.3,354l29.3,30l25.6-25h82.6L384,112.9z M324.6,112.9
|
||||
l-36.4,36.4l-53.5-53.5l36.4-36.4L324.6,112.9z M70.3,317l-3.3-3.5v-50l138-138l53.5,53.5l-138,138H70.3z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 637 B |
|
|
@ -0,0 +1,10 @@
|
|||
<?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="icons" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 384 384" style="enable-background:new 0 0 384 384;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<polygon class="st0" points="296.5,366 384,288 296.5,210.5 296.5,267 0,267 0,309 296.5,309 "/>
|
||||
<polygon class="st0" points="87.5,18 0,96 87.5,173.5 87.5,117 384,117 384,75 87.5,75 "/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 592 B |
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 23.0.4, 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 32 32" style="enable-background:new 0 0 32 32;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<path class="st0" d="M22,15h-3.4H9.9v-5c0-3.3,2.7-6,6-6H16c3,0,5.4,2.2,5.9,5h4c-0.5-5-4.8-9-9.9-9h-0.1c-5.5,0-10,4.5-10,10v5H3
|
||||
v17h12.9H16h13V15h-3H22z M18,27h-4v-7h4V27z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 581 B |
|
|
@ -997,3 +997,29 @@ app-open-wallet-modal {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
app-send-modal {
|
||||
.modal {
|
||||
|
||||
@include themify($themes) {
|
||||
background: themed(modalBackground);
|
||||
color: themed(mainTextColor);
|
||||
}
|
||||
|
||||
.title {
|
||||
|
||||
@include themify($themes) {
|
||||
border-bottom: 0.2rem solid themed(transparentButtonBorderColor);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.action-button {
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed(blueTextColor);
|
||||
color: themed(alternativeTextColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
app-contacts, app-add-contacts,
|
||||
app-contact-send, app-export-import {
|
||||
flex: 1 1 auto;
|
||||
padding: 3rem;
|
||||
min-width: 85rem;
|
||||
|
||||
.content {
|
||||
position: relative;
|
||||
padding: 3rem;
|
||||
min-height: 100%;
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed(contentBackgroundColor);
|
||||
color: themed(mainTextColor);
|
||||
}
|
||||
|
||||
.head {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
app-contacts {
|
||||
|
||||
table {
|
||||
|
||||
.alias {
|
||||
|
||||
@include themify($themes) {
|
||||
color: themed(blueTextColor);
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
|
||||
.icon {
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed(blueTextColor);
|
||||
}
|
||||
}
|
||||
|
||||
span {
|
||||
|
||||
@include themify($themes) {
|
||||
color: themed(mainTextColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
|
||||
@include themify($themes) {
|
||||
color: themed(blueTextColor);
|
||||
}
|
||||
|
||||
.import-btn {
|
||||
|
||||
@include themify($themes) {
|
||||
color: themed(blueTextColor);
|
||||
}
|
||||
|
||||
.icon {
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed(blueTextColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
app-contact-send {
|
||||
|
||||
.wallets-selection {
|
||||
|
||||
button {
|
||||
|
||||
@include themify($themes) {
|
||||
color: themed(blueTextColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -199,6 +199,13 @@ app-history {
|
|||
}
|
||||
}
|
||||
|
||||
.unlock-transaction {
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed(blueTextColor);
|
||||
}
|
||||
}
|
||||
|
||||
.status.send {
|
||||
|
||||
.status-transaction {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
@import 'assets/scss/layout/settings';
|
||||
@import 'assets/scss/layout/sidebar';
|
||||
@import 'assets/scss/layout/wallet';
|
||||
@import 'assets/scss/layout/contact';
|
||||
|
||||
// MODULES
|
||||
@import 'assets/scss/modules/head';
|
||||
|
|
|
|||