Compare commits
123 Commits
v1.5.2
...
developmen
Author | SHA1 | Date |
---|---|---|
Sean | 709008c8bc | |
Sean Darcy | 2bca9c0e7c | |
Jason Rhinelander | 4bc881e7fc | |
Sean | fbc06a407b | |
Sean | 64b38e7abc | |
Sean | a7b9274ddd | |
Sean Darcy | 3248e03924 | |
Sean Darcy | 165c140588 | |
Sean Darcy | c44a3666f3 | |
Sean | 019b8d3a9b | |
Sean | 79b9d14be5 | |
Sean | aef30512fa | |
Sean | d33ccfe0cd | |
Jason Rhinelander | ef4e62d8b0 | |
Jason Rhinelander | 6dd95d0825 | |
Jason Rhinelander | 6075dde728 | |
Ian Macdonald | 632bedb3f3 | |
Sean | 28c4c3a1d9 | |
Jason Rhinelander | 39057d95e9 | |
Jason Rhinelander | b846cd2381 | |
Sean | cd4bdee928 | |
Jason Rhinelander | 3bed654913 | |
Jason Rhinelander | fb1c853197 | |
Jeff | a3a7d8c235 | |
Sean | e81bdea2af | |
Sean Darcy | 300dcb5fab | |
Sean Darcy | ea46ff9e66 | |
Sean | f62f9ab5f3 | |
Sean Darcy | eee77f3474 | |
Sean Darcy | 9f7ab361c9 | |
Sean Darcy | 42a96ca453 | |
Sean | 56459cd174 | |
Sean Darcy | 6183d53d90 | |
Sean | 478b5305a2 | |
Sean | f19e28f930 | |
Sean | 153fbee33e | |
Ian Macdonald | f2dcaf6438 | |
Jason Rhinelander | da6e62e5ca | |
Ian Macdonald | e5a5ac031c | |
Jason Rhinelander | 2e1f0f6faa | |
Sean | 7bbfede014 | |
Sean | 6ae267abd3 | |
Sean Darcy | 86b1ab6684 | |
Sean | e06fbc31e3 | |
Sean | 6c388b895d | |
Sean | 7e3c4933fc | |
Sean | 7613cff693 | |
Sean Darcy | 05441b4689 | |
Sean Darcy | 8fd7e56795 | |
kylezs | 08bff29cce | |
Jason Rhinelander | f2eda062a2 | |
Sean | d44a9a3322 | |
Sean Darcy | 6f7cf7c00d | |
Sean Darcy | 7e311386ad | |
Sean | e7015e7d14 | |
Sean Darcy | cc847a007f | |
Sean Darcy | 9c9c089c15 | |
Sean Darcy | 8f58c716f8 | |
Sean Darcy | 030f4d5f82 | |
Sean Darcy | 8e4cb611a8 | |
Mikunj | 1b6960c636 | |
Mikunj | 8afb08936c | |
Sean | fa28657e98 | |
kylezs | 4559312e24 | |
Sean Darcy | e8088929e3 | |
kylezs | 6034e19343 | |
Sean Darcy | 8ac92f3906 | |
kylezs | 3f6f502d10 | |
Sean Darcy | 80b1d6552b | |
kylezs | ed98cde9d2 | |
kylezs | 5d3eede5f7 | |
Sean Darcy | 88b2b1bb62 | |
Sean Darcy | 8ec2399ac1 | |
Sean Darcy | c5fff0211a | |
kylezs | 35a8a7a366 | |
Jason Rhinelander | ee21b2219b | |
kylezs | 27afa67d09 | |
Jason Rhinelander | 72ff2d6b53 | |
Jason Rhinelander | 9079f4cf2b | |
Sean Darcy | 7a401a904b | |
kylezs | 2d1188f2ad | |
Sean Darcy | 1da205a4be | |
Sean Darcy | 78e8b89830 | |
kylezs | 2ecb935df7 | |
Chris Buccella | 1695b631e5 | |
kylezs | 207dce05cd | |
Chris Buccella | 332909819c | |
Sean Darcy | cb8941699d | |
kylezs | 9c42491396 | |
kylezs | 56a8373422 | |
Kyle Zsembery | 2561a4ac2c | |
Jason Rhinelander | dfbd195cc4 | |
kylezs | 1da486eb78 | |
Jason Rhinelander | cc4e870656 | |
kylezs | bdda74419b | |
kylezs | b37edea6a2 | |
Kyle Zsembery | fa6a7fea61 | |
kylezs | 873d9b167f | |
kylezs | 5c41bed273 | |
Kyle Zsembery | 726f5376f5 | |
kylezs | 99805f46fb | |
kylezs | acc69acd54 | |
Kyle Zsembery | 84d9bd9c33 | |
Kyle Zsembery | 0b2673d11d | |
kylezs | d9bda112c4 | |
kylezs | a93dc48e17 | |
kylezs | c3d0962aa7 | |
kylezs | 99ed706ec8 | |
kylezs | e80bc806ea | |
kylezs | 1e5cfb2ecc | |
kylezs | 1c726e707f | |
kylezs | 6e2f9b282b | |
Kyle Zsembery | 43291d6774 | |
kylezs | 945f35d513 | |
Kyle Zsembery | 4dbf08fa4c | |
Kyle Zsembery | d9b78c5603 | |
Kyle Zsembery | 17d17082a7 | |
Kyle Zsembery | 898f9165c2 | |
kylezs | 61bccfd590 | |
kylezs | 125c4fb1f5 | |
Kyle Zsembery | a746f529ac | |
kylezs | d670563a45 | |
Kyle Zsembery | 5a2a570afd |
|
@ -0,0 +1,100 @@
|
|||
local docker_image = 'registry.oxen.rocks/lokinet-ci-nodejs';
|
||||
|
||||
local apt_get_quiet = 'apt-get -o=Dpkg::Use-Pty=0 -q';
|
||||
|
||||
[
|
||||
{
|
||||
kind: 'pipeline',
|
||||
type: 'docker',
|
||||
name: 'Linux (amd64)',
|
||||
platform: { arch: 'amd64' },
|
||||
steps: [
|
||||
{
|
||||
name: 'build',
|
||||
image: docker_image,
|
||||
environment: {
|
||||
SSH_KEY: { from_secret: 'SSH_KEY' },
|
||||
NODE_OPTIONS: '--openssl-legacy-provider',
|
||||
},
|
||||
commands: [
|
||||
'echo "Building on ${DRONE_STAGE_MACHINE}"',
|
||||
'echo "man-db man-db/auto-update boolean false" | debconf-set-selections',
|
||||
apt_get_quiet + ' update',
|
||||
apt_get_quiet + ' install -y eatmydata',
|
||||
'eatmydata ' + apt_get_quiet + ' dist-upgrade -y',
|
||||
'./tools/download-oxen-files.sh https://oxen.rocks/oxen-io/oxen-core/oxen-stable-linux-LATEST.tar.xz',
|
||||
'npm --version',
|
||||
'node --version',
|
||||
'mkdir -p $CCACHE_DIR/electron-builder',
|
||||
'mkdir -p $CCACHE_DIR/npm',
|
||||
'npm ci --cache $CCACHE_DIR/npm',
|
||||
'ELECTRON_BUILDER_CACHE=$CCACHE_DIR/electron-builder npm --cache $CCACHE_DIR/npm run build',
|
||||
'./tools/ci-drone-static-upload.sh',
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
kind: 'pipeline',
|
||||
type: 'docker',
|
||||
name: 'Windows (x64)',
|
||||
platform: { arch: 'amd64' },
|
||||
steps: [
|
||||
{
|
||||
name: 'build',
|
||||
image: docker_image,
|
||||
environment: {
|
||||
SSH_KEY: { from_secret: 'SSH_KEY' },
|
||||
WINEDEBUG: '-all',
|
||||
NODE_OPTIONS: '--openssl-legacy-provider',
|
||||
},
|
||||
commands: [
|
||||
'echo "Building on ${DRONE_STAGE_MACHINE}"',
|
||||
'echo "man-db man-db/auto-update boolean false" | debconf-set-selections',
|
||||
apt_get_quiet + ' update',
|
||||
apt_get_quiet + ' install -y eatmydata zip',
|
||||
'eatmydata ' + apt_get_quiet + ' dist-upgrade -y',
|
||||
'./tools/download-oxen-files.sh https://oxen.rocks/oxen-io/oxen-core/oxen-stable-win-LATEST.zip',
|
||||
'wine bin/oxend.exe --version',
|
||||
'wine bin/oxen-wallet-rpc.exe --version',
|
||||
'npm --version',
|
||||
'node --version',
|
||||
'mkdir -p $CCACHE_DIR/electron-builder',
|
||||
'mkdir -p $CCACHE_DIR/npm',
|
||||
'npm ci --cache $CCACHE_DIR/npm',
|
||||
'ELECTRON_BUILDER_CACHE=$CCACHE_DIR/electron-builder npm --cache $CCACHE_DIR/npm run windows',
|
||||
'./tools/ci-drone-static-upload.sh',
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
kind: 'pipeline',
|
||||
type: 'exec',
|
||||
name: 'MacOS (unsigned)',
|
||||
platform: { os: 'darwin', arch: 'amd64' },
|
||||
steps: [
|
||||
{
|
||||
name: 'build',
|
||||
environment: {
|
||||
SSH_KEY: { from_secret: 'SSH_KEY' },
|
||||
CSC_IDENTITY_AUTO_DISCOVERY: 'false',
|
||||
},
|
||||
commands: [
|
||||
'echo "Building on ${DRONE_STAGE_MACHINE}"',
|
||||
'./tools/download-oxen-files.sh https://oxen.rocks/oxen-io/oxen-core/oxen-stable-macos-LATEST.tar.xz',
|
||||
'npm --version',
|
||||
'node --version',
|
||||
'mkdir -p $CCACHE_DIR/electron-builder',
|
||||
'mkdir -p $CCACHE_DIR/npm',
|
||||
'npm ci --cache $CCACHE_DIR/npm',
|
||||
'ELECTRON_BUILDER_CACHE=$CCACHE_DIR/electron-builder WINEDEBUG=-all npm --cache $CCACHE_DIR/npm run build',
|
||||
'./tools/ci-drone-static-upload.sh',
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
]
|
|
@ -1,89 +0,0 @@
|
|||
name: Loki Electron Wallet Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- development
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [windows-latest, macos-latest, ubuntu-latest]
|
||||
steps:
|
||||
- name: Checkout git repo
|
||||
uses: actions/checkout@v1
|
||||
|
||||
# Read node version from `.nvmrc` file
|
||||
- name: Read nvm rc
|
||||
id: nvmrc
|
||||
uses: browniebroke/read-nvmrc-action@v1
|
||||
|
||||
- name: Install node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ steps.nvmrc.outputs.node_version }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Download lokid binaries
|
||||
run: ./download-asset.sh
|
||||
env:
|
||||
OS: ${{ runner.os }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
shell: bash
|
||||
working-directory: ./downloads
|
||||
|
||||
- name: Extract zip binaries
|
||||
if: runner.os == 'Windows'
|
||||
run: unzip latest
|
||||
shell: bash
|
||||
working-directory: ./downloads
|
||||
|
||||
- name: Extract xz binaries
|
||||
if: runner.os != 'Windows'
|
||||
run: tar -xf latest
|
||||
shell: bash
|
||||
working-directory: ./downloads
|
||||
|
||||
- name: Move lokid binaries
|
||||
run: |
|
||||
find ./downloads -type f -name "lokid*" -exec cp '{}' ./bin \;
|
||||
find ./downloads -type f -name "loki-wallet-rpc*" -exec cp '{}' ./bin \;
|
||||
shell: bash
|
||||
|
||||
- name: Verify binaries
|
||||
run: ls ./bin
|
||||
shell: bash
|
||||
|
||||
- name: Build window and linux binaries
|
||||
if: runner.os != 'macOS'
|
||||
run: npm run build
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build mac binaries
|
||||
if: runner.os == 'macOS'
|
||||
run: npm run build
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
CSC_LINK: ${{ secrets.MAC_CERTIFICATE }}
|
||||
CSC_KEY_PASSWORD: ${{ secrets.MAC_CERTIFICATE_PASSWORD }}
|
||||
SIGNING_APPLE_ID: ${{ secrets.SIGNING_APPLE_ID }}
|
||||
SIGNING_APP_PASSWORD: ${{ secrets.SIGNING_APP_PASSWORD }}
|
||||
SIGNING_TEAM_ID: ${{ secrets.SIGNING_TEAM_ID }}
|
||||
|
||||
- name: Remove un-needed artifacts
|
||||
run: rm -r -- ./*/
|
||||
shell: bash
|
||||
working-directory: ./dist/electron/Packaged
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: ${{ runner.OS }}
|
||||
path: dist/electron/Packaged
|
|
@ -1,87 +0,0 @@
|
|||
name: Loki Electron Wallet With Dev Binaries
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev-bins
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [windows-latest, macos-latest, ubuntu-latest]
|
||||
steps:
|
||||
- name: Checkout git repo
|
||||
uses: actions/checkout@v1
|
||||
|
||||
# Read node version from `.nvmrc` file
|
||||
- name: Read nvm rc
|
||||
id: nvmrc
|
||||
uses: browniebroke/read-nvmrc-action@v1
|
||||
|
||||
- name: Install node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ steps.nvmrc.outputs.node_version }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Download lokid binaries
|
||||
run: ./download-dev-bins.sh
|
||||
env:
|
||||
OS: ${{ runner.os }}
|
||||
shell: bash
|
||||
working-directory: ./downloads
|
||||
|
||||
- name: Extract zip binaries
|
||||
if: runner.os == 'Windows'
|
||||
run: unzip latest
|
||||
shell: bash
|
||||
working-directory: ./downloads
|
||||
|
||||
- name: Extract xz binaries
|
||||
if: runner.os != 'Windows'
|
||||
run: tar -xf latest
|
||||
shell: bash
|
||||
working-directory: ./downloads
|
||||
|
||||
- name: Move lokid binaries
|
||||
run: |
|
||||
find ./downloads -type f -name "lokid*" -exec cp '{}' ./bin \;
|
||||
find ./downloads -type f -name "loki-wallet-rpc*" -exec cp '{}' ./bin \;
|
||||
shell: bash
|
||||
|
||||
- name: Verify binaries
|
||||
run: ls ./bin
|
||||
shell: bash
|
||||
|
||||
- name: Build window and linux binaries
|
||||
if: runner.os != 'macOS'
|
||||
run: npm run build
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build mac binaries
|
||||
if: runner.os == 'macOS'
|
||||
run: npm run build
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
CSC_LINK: ${{ secrets.MAC_CERTIFICATE }}
|
||||
CSC_KEY_PASSWORD: ${{ secrets.MAC_CERTIFICATE_PASSWORD }}
|
||||
SIGNING_APPLE_ID: ${{ secrets.SIGNING_APPLE_ID }}
|
||||
SIGNING_APP_PASSWORD: ${{ secrets.SIGNING_APP_PASSWORD }}
|
||||
SIGNING_TEAM_ID: ${{ secrets.SIGNING_TEAM_ID }}
|
||||
|
||||
- name: Remove un-needed artifacts
|
||||
run: rm -r -- ./*/
|
||||
shell: bash
|
||||
working-directory: ./dist/electron/Packaged
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: ${{ runner.OS }}
|
||||
path: dist/electron/Packaged
|
|
@ -1,77 +0,0 @@
|
|||
name: Loki Electron Wallet Release
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [windows-latest, macos-latest, ubuntu-latest]
|
||||
steps:
|
||||
- name: Checkout git repo
|
||||
uses: actions/checkout@v1
|
||||
|
||||
# Read node version from `.nvmrc` file
|
||||
- name: Read nvm rc
|
||||
id: nvmrc
|
||||
uses: browniebroke/read-nvmrc-action@v1
|
||||
|
||||
- name: Install node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ steps.nvmrc.outputs.node_version }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Download lokid binaries
|
||||
run: ./download-asset.sh
|
||||
env:
|
||||
OS: ${{ runner.os }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
shell: bash
|
||||
working-directory: ./downloads
|
||||
|
||||
- name: Extract zip binaries
|
||||
if: runner.os == 'Windows'
|
||||
run: unzip latest
|
||||
shell: bash
|
||||
working-directory: ./downloads
|
||||
|
||||
- name: Extract xz binaries
|
||||
if: runner.os != 'Windows'
|
||||
run: tar -xf latest
|
||||
shell: bash
|
||||
working-directory: ./downloads
|
||||
|
||||
- name: Move lokid binaries
|
||||
run: |
|
||||
find ./downloads -type f -name "lokid*" -exec cp '{}' ./bin \;
|
||||
find ./downloads -type f -name "loki-wallet-rpc*" -exec cp '{}' ./bin \;
|
||||
shell: bash
|
||||
|
||||
- name: Verify binaries
|
||||
run: ls ./bin
|
||||
shell: bash
|
||||
|
||||
- name: Publish window and linux binaries
|
||||
if: runner.os != 'macOS'
|
||||
run: npm run release
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Publish mac binaries
|
||||
if: runner.os == 'macOS'
|
||||
run: npm run release
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
CSC_LINK: ${{ secrets.MAC_CERTIFICATE }}
|
||||
CSC_KEY_PASSWORD: ${{ secrets.MAC_CERTIFICATE_PASSWORD }}
|
||||
SIGNING_APPLE_ID: ${{ secrets.SIGNING_APPLE_ID }}
|
||||
SIGNING_APP_PASSWORD: ${{ secrets.SIGNING_APP_PASSWORD }}
|
||||
SIGNING_TEAM_ID: ${{ secrets.SIGNING_TEAM_ID }}
|
63
BUILDING.md
|
@ -1,42 +1,43 @@
|
|||
# Building
|
||||
|
||||
Building loki electron wallet binaries is done using github actions. Windows and linux binaries will build right out of the box but there are some extra steps needed for Mac OS
|
||||
Set up the supported versions of npm/node/etc.:
|
||||
|
||||
## Mac OS
|
||||
nvm use
|
||||
|
||||
The build script for Mac OS requires you to have a valid `Developer ID Application` certificate. Without this the build script cannot sign and notarize the mac binary which is needed for Catalina 10.15 and above.
|
||||
If you would like to disable this then comment out `"afterSign": "build/notarize.js",` in package.json.
|
||||
## Linux, Windows
|
||||
|
||||
You will also need an [App-specific password](https://support.apple.com/en-al/HT204397) for the apple account you wish to notarize with
|
||||
npm run build
|
||||
|
||||
### Setup
|
||||
## MacOS
|
||||
|
||||
Once you have your `Developer ID Application` you need to export it into a `.p12` file. Keep a note of the password used to encrypt this file as it will be needed later.
|
||||
If you don't care about signing (i.e. you are not going to distribute) then you should be able to
|
||||
simply `npm run build`.
|
||||
|
||||
We need to Base64 encode this file, so run the following command:
|
||||
When you want to distribute the app, however, you need to do a bunch of crap to satisfy Apple's
|
||||
arbitrary security theatre Rube Goldberg machine that purports to keep users safe but in reality is
|
||||
designed to further Apple lock-in control of the Apple ecosystem.
|
||||
|
||||
```
|
||||
base64 -i certificate.p12 -o encoded.txt
|
||||
```
|
||||
1. You have to pay Apple money (every year) to get a developer account.
|
||||
2. You need a `Developer ID Application` certificate, created and signed from the Apple, and loaded
|
||||
into your system keychain. `security find-identity -v` should show it.
|
||||
3. You need to create an [App-specific password](https://support.apple.com/en-al/HT204397) for the
|
||||
Apple developer account under which you are notarizing.
|
||||
4. In the project root, create a `.env` file with contents:
|
||||
|
||||
#### On GitHub:
|
||||
SIGNING_APPLE_ID=your-developer-id@example.com
|
||||
SIGNING_APP_PASSWORD=app-specific-password
|
||||
|
||||
1. Navigate to the main page of the repository.
|
||||
2. Under your repository name, click **Settings**.
|
||||
3. In the left sidebar, click **Secrets**.
|
||||
4. Add the following secrets:
|
||||
1. Certificate
|
||||
- Name: `MAC_CERTIFICATE`
|
||||
- Value: The encoded Base64 certificate
|
||||
2. Certificate password
|
||||
- Name: `MAC_CERTIFICATE_PASSWORD`
|
||||
- Value: The password that was set when the certificate was exported.
|
||||
3. Apple ID
|
||||
- Name: `SIGNING_APPLE_ID`
|
||||
- Value: The apple id (email) to use for signing
|
||||
4. Apple Password
|
||||
- Name: `SIGNING_APP_PASSWORD`
|
||||
- Value: The app-specific password that was generated for the apple id
|
||||
5. Team ID (Optional)
|
||||
- Name: `SIGNING_TEAM_ID`
|
||||
- Value: The apple team id if you're sigining the application for a team
|
||||
This password can be plaintext if absolutely needed (e.g. in a CI job) but should be a [keychain
|
||||
reference](https://github.com/electron/electron-notarize#safety-when-using-appleidpassword) such
|
||||
as `@keychain:some-token` for better security where feasible.
|
||||
|
||||
- If you have multiple ids and need to use a particular signing team ID you can add:
|
||||
|
||||
SIGNING_TEAM_ID=TEAMIDXYZ1
|
||||
|
||||
5. If building from a remote connection (e.g. ssh'd into a mac) then unlock the keychain for that
|
||||
session by running `security unlock`.
|
||||
|
||||
With all of that set up, your `npm run build` should produce a signed and notarized installer.
|
||||
Hopefully. Maybe. Sometimes Apple's servers are broken and you might have to try again. But don't
|
||||
worry, Apple's incompetence around signing makes everything more secure because... reasons.
|
||||
|
|
24
README.md
|
@ -1,34 +1,32 @@
|
|||
# Loki Electron GUI Wallet
|
||||
# Oxen Electron GUI Wallet
|
||||
|
||||
### Introduction
|
||||
|
||||
Loki is a private cryptocurrency based on Monero. Loki aims to provide a private data transmission layer using a second layer of Service Nodes.
|
||||
More information on the project can be found on the [website](https://loki.network) and in the [whitepaper](https://loki.network/whitepaper). Loki is an open source project, and we encourage contributions from anyone with something to offer.
|
||||
Oxen (formerly Loki) is a private cryptocurrency based on Monero. Oxen aims to provide a private data transmission layer using a second layer of Service Nodes.
|
||||
More information on the project can be found on the [website](https://oxen.io) and in the [whitepaper](https://loki.network/whitepaper). Oxen is an open source project, and we encourage contributions from anyone with something to offer.
|
||||
|
||||
<p align="center">
|
||||
<img src="https://raw.githubusercontent.com/KeeJef/loki-electron-gui-wallet/master/src-electron/icons/mrcuug.PNG" width="600">
|
||||
</p>
|
||||
![Oxen wallet image](./src-electron/icons/mrcuug.PNG)
|
||||
|
||||
### About this project
|
||||
|
||||
This is the new electron GUI for Loki. It is open source and completely free to use without restrictions, anyone may create an alternative implementation of the Loki Electron GUI that uses the protocol and network in a compatible manner.
|
||||
This is the new Electron GUI for Oxen. It is open source and completely free to use without restrictions, anyone may create an alternative implementation of the Oxen Electron GUI that uses the protocol and network in a compatible manner.
|
||||
|
||||
Please submit any changes as pull requests to the development branch, all changes are assessed in the development branch before being merged to master, release tags are considered stable builds for the GUI.
|
||||
|
||||
#### Pre-requisites
|
||||
|
||||
- Download latest [Lokid](https://github.com/loki-project/loki/releases/latest)
|
||||
- Extract the lokid binaries to a folder
|
||||
- Download latest [oxend](https://github.com/oxen-io/oxen-core/releases/latest)
|
||||
- Extract the oxend binaries to a folder
|
||||
|
||||
#### Commands
|
||||
|
||||
```
|
||||
nvm use 14.11.0
|
||||
npm install -g @quasar/cli
|
||||
git clone https://github.com/loki-project/loki-electron-gui-wallet
|
||||
cd loki-electron-gui-wallet
|
||||
cp path_to_lokid_binaries/lokid bin/
|
||||
cp path_to_lokid_binaries/loki-wallet-rpc bin/
|
||||
git clone https://github.com/oxen-io/oxen-electron-gui-wallet
|
||||
cd oxen-electron-gui-wallet
|
||||
cp path_to_oxend_binaries/oxend bin/
|
||||
cp path_to_oxend_binaries/oxen-wallet-rpc bin/
|
||||
npm install
|
||||
```
|
||||
|
||||
|
|
|
@ -22,19 +22,25 @@ exports.default = async function notarizing(context) {
|
|||
log("Notarizing mac application");
|
||||
|
||||
const appName = context.packager.appInfo.productFilename;
|
||||
const { SIGNING_APPLE_ID, SIGNING_APP_PASSWORD, SIGNING_TEAM_ID } = process.env;
|
||||
const {
|
||||
SIGNING_APPLE_ID,
|
||||
SIGNING_APP_PASSWORD,
|
||||
SIGNING_TEAM_ID
|
||||
} = process.env;
|
||||
|
||||
if (isEmpty(SIGNING_APPLE_ID) || isEmpty(SIGNING_APP_PASSWORD)) {
|
||||
log("SIGNING_APPLE_ID or SIGNING_APP_PASSWORD not set.\nTerminating noratization.");
|
||||
log(
|
||||
"SIGNING_APPLE_ID or SIGNING_APP_PASSWORD not set.\nTerminating noratization."
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const options = {
|
||||
appBundleId: "com.loki-project.electron-wallet",
|
||||
tool: "notarytool",
|
||||
appPath: `${appOutDir}/${appName}.app`,
|
||||
appleId: SIGNING_APPLE_ID,
|
||||
appleIdPassword: SIGNING_APP_PASSWORD
|
||||
};
|
||||
if (!isEmpty(SIGNING_TEAM_ID)) options.ascProvider = SIGNING_TEAM_ID;
|
||||
if (!isEmpty(SIGNING_TEAM_ID)) options.teamId = SIGNING_TEAM_ID;
|
||||
return notarize(options);
|
||||
};
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
#!/bin/bash
|
||||
# Source from: https://github.com/houqp/download-release-assets-action
|
||||
|
||||
set -e
|
||||
|
||||
if [ -z "$OS" ]; then
|
||||
echo "OS must be set"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$RENAME" ]; then
|
||||
RENAME="latest"
|
||||
fi
|
||||
|
||||
REPO="loki-project/loki-core"
|
||||
RELEASE="latest"
|
||||
|
||||
if [ "$OS" == "Linux" ]; then
|
||||
FILE_NAME_REGEX="linux"
|
||||
elif [ "$OS" == "Windows" ]; then
|
||||
FILE_NAME_REGEX="win"
|
||||
elif [ "$OS" == "macOS" ]; then
|
||||
FILE_NAME_REGEX="macos"
|
||||
else
|
||||
echo "OS must be Linux, Windows or macOS"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
ASSET_URL=$(curl -sL --fail \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
-H "Authorization: Bearer ${GITHUB_TOKEN}" \
|
||||
"https://api.github.com/repos/${REPO}/releases/${RELEASE}" \
|
||||
| jq -r ".assets | .[] | select(.name | test(\"${FILE_NAME_REGEX}\")) | .url")
|
||||
|
||||
curl -sL --fail \
|
||||
-H "Accept: application/octet-stream" \
|
||||
-H "Authorization: Bearer ${GITHUB_TOKEN}" \
|
||||
-o "${RENAME}" \
|
||||
"$ASSET_URL"
|
|
@ -1,32 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
if [ -z "$OS" ]; then
|
||||
echo "OS must be set"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$RENAME" ]; then
|
||||
RENAME="latest"
|
||||
fi
|
||||
|
||||
if [ "$OS" == "Linux" ]; then
|
||||
ASSET_URL="https://builds.lokinet.dev/loki-project/loki-core/loki-dev-linux-LATEST.tar.xz"
|
||||
elif [ "$OS" == "Windows" ]; then
|
||||
ASSET_URL="https://builds.lokinet.dev/loki-project/loki-core/loki-dev-win-LATEST.zip"
|
||||
elif [ "$OS" == "macOS" ]; then
|
||||
ASSET_URL="https://builds.lokinet.dev/loki-project/loki-core/loki-dev-macos-LATEST.tar.xz"
|
||||
else
|
||||
echo "OS must be Linux, Windows or macOS"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "About to download the binaries"
|
||||
|
||||
curl -sL --fail \
|
||||
-H "Accept: application/octet-stream" \
|
||||
-o "${RENAME}" \
|
||||
"$ASSET_URL"
|
||||
|
||||
echo "Loki binaries downloaded"
|
19
package.json
|
@ -1,22 +1,22 @@
|
|||
{
|
||||
"name": "loki-electron-wallet",
|
||||
"version": "1.5.2",
|
||||
"description": "Modern GUI interface for Loki Currency",
|
||||
"productName": "Loki Electron Wallet",
|
||||
"name": "oxen-electron-wallet",
|
||||
"version": "1.8.1",
|
||||
"description": "Modern GUI interface for Oxen Currency",
|
||||
"productName": "Oxen Electron Wallet",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/loki-project/loki-electron-gui-wallet.git"
|
||||
},
|
||||
"cordovaId": "com.lokinetwork.wallet",
|
||||
"cordovaId": "com.oxen.wallet",
|
||||
"author": {
|
||||
"name": "Loki Project",
|
||||
"email": "team@loki.network"
|
||||
"name": "Oxen",
|
||||
"email": "oxen@oxen.io"
|
||||
},
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "quasar dev -m electron",
|
||||
"build": "quasar build -m electron --publish=never",
|
||||
"release": "quasar build -m electron --publish=always",
|
||||
"windows": "quasar build -m electron --publish=never -T win",
|
||||
"lint": "eslint --fix .",
|
||||
"format": "prettier --write \"**/*.+(js|jsx|json|yml|yaml|css|md|vue)\"",
|
||||
"ready": "npm run lint && npm run format"
|
||||
|
@ -48,7 +48,7 @@
|
|||
"devtron": "^1.4.0",
|
||||
"dotenv": "^8.1.0",
|
||||
"electron": "^4.1.1",
|
||||
"electron-builder": "^22.4.1",
|
||||
"electron-builder": "^23.0.3",
|
||||
"electron-debug": "^2.1.0",
|
||||
"electron-devtools-installer": "^2.2.4",
|
||||
"electron-notarize": "^0.1.1",
|
||||
|
@ -63,7 +63,6 @@
|
|||
"eslint-plugin-vue": "^5.2.3",
|
||||
"husky": "^4.2.3",
|
||||
"lint-staged": "^10.0.8",
|
||||
"node-sass": "^4.13.1",
|
||||
"prettier": "^1.19.1",
|
||||
"sass-loader": "^7.1.0",
|
||||
"strip-ansi": "^3.0.1"
|
||||
|
|
After Width: | Height: | Size: 30 KiB |
|
@ -1,66 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 22.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 1000 368" style="enable-background:new 0 0 1000 368;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
.st1{fill:url(#SVGID_1_);}
|
||||
.st2{fill:#333333;}
|
||||
.st3{fill:url(#SVGID_2_);}
|
||||
.st4{fill:url(#SVGID_3_);}
|
||||
.st5{fill:#00263A;}
|
||||
.st6{fill:url(#SVGID_4_);}
|
||||
.st7{fill:url(#SVGID_5_);}
|
||||
.st8{fill:url(#SVGID_6_);}
|
||||
.st9{fill:url(#SVGID_7_);}
|
||||
.st10{fill:url(#SVGID_8_);}
|
||||
.st11{fill:url(#SVGID_9_);}
|
||||
.st12{fill:url(#SVGID_10_);}
|
||||
.st13{fill:url(#SVGID_11_);}
|
||||
.st14{fill:url(#SVGID_12_);}
|
||||
.st15{fill:url(#SVGID_13_);}
|
||||
.st16{fill:url(#SVGID_14_);}
|
||||
.st17{fill:url(#SVGID_15_);}
|
||||
.st18{fill:url(#SVGID_16_);}
|
||||
.st19{fill:url(#SVGID_17_);}
|
||||
.st20{opacity:6.000000e-02;}
|
||||
.st21{opacity:4.000000e-02;fill:#FFFFFF;}
|
||||
.st22{opacity:7.000000e-02;fill:#FFFFFF;}
|
||||
.st23{fill:#008522;}
|
||||
.st24{fill:#78BE20;}
|
||||
.st25{fill:#005F61;}
|
||||
.st26{fill:url(#SVGID_18_);}
|
||||
</style>
|
||||
<g>
|
||||
<path class="st0" d="M366.6,78h37.1v178.9H497v32.7H366.6V78z"/>
|
||||
<path class="st0" d="M619.8,74.5C683.3,74.5,728,120.8,728,184c0,63.1-44.7,109.5-108.2,109.5c-63.5,0-108.2-46.3-108.2-109.5
|
||||
C511.6,120.8,556.3,74.5,619.8,74.5z M619.8,107.5c-42.8,0-70.1,32.7-70.1,76.5c0,43.5,27.3,76.5,70.1,76.5
|
||||
c42.5,0,70.1-33,70.1-76.5C689.9,140.2,662.3,107.5,619.8,107.5z"/>
|
||||
<path class="st0" d="M819.4,200.5L801,222v67.6h-37.1V78H801v100.9L883.8,78h46l-86,99.9l92.3,111.7h-45.7L819.4,200.5z"/>
|
||||
<path class="st0" d="M960.9,78H998v211.6h-37.1V78z"/>
|
||||
</g>
|
||||
<g>
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="86.8402" y1="268.7968" x2="86.8402" y2="0.426">
|
||||
<stop offset="0" style="stop-color:#78BE20"/>
|
||||
<stop offset="0.1197" style="stop-color:#58AF21"/>
|
||||
<stop offset="0.3682" style="stop-color:#199122"/>
|
||||
<stop offset="0.486" style="stop-color:#008522"/>
|
||||
<stop offset="0.6925" style="stop-color:#007242"/>
|
||||
<stop offset="0.8806" style="stop-color:#006459"/>
|
||||
<stop offset="1" style="stop-color:#005F61"/>
|
||||
</linearGradient>
|
||||
<polygon class="st1" points="132.1,268.8 0.3,137 136.9,0.4 173.3,36.8 73.1,137 168.5,232.4 "/>
|
||||
</g>
|
||||
<g>
|
||||
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="212.9564" y1="367.5197" x2="212.9564" y2="99.1484">
|
||||
<stop offset="0" style="stop-color:#78BE20"/>
|
||||
<stop offset="0.1197" style="stop-color:#58AF21"/>
|
||||
<stop offset="0.3682" style="stop-color:#199122"/>
|
||||
<stop offset="0.486" style="stop-color:#008522"/>
|
||||
<stop offset="0.6925" style="stop-color:#007242"/>
|
||||
<stop offset="0.8806" style="stop-color:#006459"/>
|
||||
<stop offset="1" style="stop-color:#005F61"/>
|
||||
</linearGradient>
|
||||
<polygon class="st3" points="162.9,367.5 126.5,331.1 226.7,230.9 131.3,135.6 167.7,99.1 299.5,230.9 "/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 210 KiB |
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 25.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 1501.3 321.3" style="enable-background:new 0 0 1501.3 321.3;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
.st1{fill:#12C7BA;}
|
||||
</style>
|
||||
<g>
|
||||
<g>
|
||||
<path class="st0" d="M886.1,75.7l-65,56l-65-56c-5.2-4.5-11.9-7-18.8-7l-56.5,0l106.7,91.9l-106.7,91.9l56.5,0
|
||||
c6.9,0,13.6-2.5,18.8-7l65-56l65,56c5.2,4.5,11.9,7,18.8,7l56.5,0l-106.7-91.9l106.7-91.9h-56.5C898,68.7,891.3,71.2,886.1,75.7z"
|
||||
/>
|
||||
<path class="st0" d="M1501.3,68.7h-43v128.4L1299.2,74.7c-5-3.9-11.2-6-17.6-6h-30.9v183.9h43V124.2l159.1,122.4
|
||||
c5,3.9,11.2,6,17.6,6h30.9V68.7z"/>
|
||||
<path class="st0" d="M1212,107.9V68.7l-205.7,0c-22.5,25.9-34.5,58-34.5,91.9c0,33.9,12,66.1,34.5,91.9H1212v-39.1h-184.4
|
||||
c-5.1-9.6-8.8-20.3-10.7-33.2h180.3v-41.1h-180c2-12,5.6-22.2,10.4-31.3H1212z"/>
|
||||
<path class="st0" d="M674.4,160.7c0-55.4-34-91.9-34-91.9l-193.1,0c0,0-34,36.6-34,91.9s34,91.9,34,91.9h193.1
|
||||
C640.4,252.6,674.4,216,674.4,160.7z M469.6,213.2c-8.7-15.8-13.3-33.9-13.3-52.5c0-18.6,4.6-36.7,13.3-52.5h148.6
|
||||
c8.7,15.8,13.3,33.9,13.3,52.5c0,18.6-4.6,36.7-13.3,52.5H469.6z"/>
|
||||
</g>
|
||||
<g>
|
||||
<circle class="st0" cx="160.6" cy="160.6" r="160.6"/>
|
||||
<g>
|
||||
<polygon class="st1" points="67.6,80.5 160.6,160.6 253.7,80.5 "/>
|
||||
<polygon class="st1" points="253.7,240.8 160.6,160.6 67.6,240.8 "/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 214 KiB |
|
@ -156,19 +156,33 @@ module.exports = function() {
|
|||
builder: {
|
||||
// https://www.electron.build/configuration/configuration
|
||||
|
||||
appId: "com.loki-project.electron-wallet",
|
||||
productName: "Loki Electron Wallet",
|
||||
copyright:
|
||||
"Copyright © 2018-2020 Loki Project, 2018 Ryo Currency Project",
|
||||
appId: "com.oxen.electron-wallet",
|
||||
productName: "Oxen Electron Wallet",
|
||||
copyright: "Copyright © 2018-2022 Oxen, 2018 Ryo Currency Project",
|
||||
afterSign: "build/notarize.js",
|
||||
artifactName: "loki-electron-wallet-${version}-${os}.${ext}",
|
||||
artifactName: "oxen-electron-wallet-${version}-${os}.${ext}",
|
||||
publish: "github",
|
||||
|
||||
linux: {
|
||||
target: ["AppImage", "deb"],
|
||||
icon: "src-electron/icons/icon_512x512.png",
|
||||
icon: "oxen-electron-wallet.png",
|
||||
category: "Finance"
|
||||
},
|
||||
// see https://www.electron.build/configuration/linux#debian-package-options
|
||||
deb: {
|
||||
depends: [
|
||||
"libgtk-3-0",
|
||||
"libnotify4",
|
||||
"libnss3",
|
||||
"libxss1",
|
||||
"libxtst6",
|
||||
"xdg-utils",
|
||||
"libatspi2.0-0",
|
||||
"libuuid1",
|
||||
"libsecret-1-0",
|
||||
"libappindicator3-1 | libayatana-appindicator3-1"
|
||||
]
|
||||
},
|
||||
|
||||
mac: {
|
||||
// We need zip for auto-updating
|
||||
|
@ -184,7 +198,7 @@ module.exports = function() {
|
|||
},
|
||||
|
||||
dmg: {
|
||||
background: "src-electron/build/loki-dmg.tiff",
|
||||
background: "src-electron/build/oxen-dmg.tiff",
|
||||
sign: false
|
||||
},
|
||||
|
||||
|
|
Before Width: | Height: | Size: 114 KiB After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 197 KiB |
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 197 KiB |
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 197 KiB |
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 408 KiB |
|
@ -21,7 +21,10 @@ async function canAutoUpdate() {
|
|||
|
||||
// Taken from: https://github.com/electron-userland/electron-builder/blob/d4feb6d3c8b008f8b455c761d654c8088f90d8fa/packages/electron-updater/src/ElectronAppAdapter.ts#L25
|
||||
const updateFile = isPackaged ? "app-update.yml" : "dev-app-update.yml";
|
||||
const basePath = isPackaged && process.resourcesPath ? process.resourcesPath : app.getAppPath();
|
||||
const basePath =
|
||||
isPackaged && process.resourcesPath
|
||||
? process.resourcesPath
|
||||
: app.getAppPath();
|
||||
const appUpdateConfigPath = path.join(basePath, updateFile);
|
||||
|
||||
return new Promise(resolve => {
|
||||
|
@ -96,8 +99,8 @@ async function showUpdateDialog(mainWindow) {
|
|||
const options = {
|
||||
type: "info",
|
||||
buttons: ["Restart Wallet", "Later"],
|
||||
title: "Loki Electron Wallet update available",
|
||||
message: "There is a new version of Loki Electron Wallet available.",
|
||||
title: "Oxen Electron Wallet update available",
|
||||
message: "There is a new version of Oxen Electron Wallet available.",
|
||||
detail: "Press Restart Wallet to apply the update",
|
||||
defaultId: LATER_BUTTON,
|
||||
cancelId: RESTART_BUTTON
|
||||
|
@ -115,7 +118,7 @@ async function showCannotUpdateDialog(mainWindow) {
|
|||
buttons: ["Ok"],
|
||||
title: "Cannot update",
|
||||
message:
|
||||
"Loki Electron Wallet failed to update but there is a new version available. Please go to https://loki.network/ and install the new version manually."
|
||||
"Oxen Electron Wallet failed to update but there is a new version available. Please go to https://oxen.io/ and install the new version manually."
|
||||
};
|
||||
|
||||
return new Promise(resolve => {
|
||||
|
|
|
@ -13,7 +13,7 @@ const path = require("upath");
|
|||
* The reason we are setting it here is that the path needs to be evaluated at runtime
|
||||
*/
|
||||
if (process.env.PROD) {
|
||||
global.__statics = path.join(__dirname, "statics").replace(/\\/g, "\\\\");
|
||||
global.__statics = path.join(__dirname, "").replace(/\\/g, "\\\\");
|
||||
global.__ryo_bin = path.join(__dirname, "..", "bin").replace(/\\/g, "\\\\");
|
||||
} else {
|
||||
global.__ryo_bin = path.join(process.cwd(), "bin").replace(/\\/g, "\\\\");
|
||||
|
@ -57,7 +57,7 @@ function createWindow() {
|
|||
height: mainWindowState.height,
|
||||
minWidth: 640,
|
||||
minHeight: 480,
|
||||
icon: require("path").join(__statics, "icon_512x512.png"),
|
||||
icon: require("path").join(__statics, "icon.png"),
|
||||
title,
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
|
@ -137,7 +137,7 @@ function createWindow() {
|
|||
mainWindow,
|
||||
{
|
||||
title: "Startup error",
|
||||
message: `Loki Wallet is already open, or port ${config.port} is in use`,
|
||||
message: `Oxen Wallet is already open, or port ${config.port} is in use`,
|
||||
type: "error",
|
||||
buttons: ["ok"]
|
||||
},
|
||||
|
|
|
@ -33,7 +33,7 @@ let template = [
|
|||
{
|
||||
label: "Learn More",
|
||||
click() {
|
||||
require("electron").shell.openExternal("https://loki.network/");
|
||||
require("electron").shell.openExternal("https://oxen.io/");
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -42,7 +42,7 @@ let template = [
|
|||
|
||||
if (process.platform === "darwin") {
|
||||
template.unshift({
|
||||
label: "Loki Electron Wallet",
|
||||
label: "Oxen Electron Wallet",
|
||||
submenu: [
|
||||
{ role: "about" },
|
||||
{ type: "separator" },
|
||||
|
|
|
@ -34,16 +34,27 @@ export class Backend {
|
|||
}
|
||||
|
||||
init(config) {
|
||||
let configDir;
|
||||
let legacyLokiConfigDir;
|
||||
if (os.platform() === "win32") {
|
||||
this.config_dir = "C:\\ProgramData\\loki";
|
||||
this.wallet_dir = `${os.homedir()}\\Documents\\Loki`;
|
||||
configDir = "C:\\ProgramData\\oxen";
|
||||
legacyLokiConfigDir = "C:\\ProgramData\\loki\\";
|
||||
this.wallet_dir = `${os.homedir()}\\Documents\\Oxen`;
|
||||
} else {
|
||||
this.config_dir = path.join(os.homedir(), ".loki");
|
||||
this.wallet_dir = path.join(os.homedir(), "Loki");
|
||||
configDir = path.join(os.homedir(), ".oxen");
|
||||
legacyLokiConfigDir = path.join(os.homedir(), ".loki/");
|
||||
this.wallet_dir = path.join(os.homedir(), "Oxen");
|
||||
}
|
||||
|
||||
if (!fs.existsSync(this.config_dir)) {
|
||||
fs.mkdirpSync(this.config_dir);
|
||||
// if the user has used loki before, just keep the same stuff
|
||||
if (fs.existsSync(legacyLokiConfigDir)) {
|
||||
this.config_dir = legacyLokiConfigDir;
|
||||
} else {
|
||||
// create the new, Oxen location
|
||||
this.config_dir = configDir;
|
||||
if (!fs.existsSync(configDir)) {
|
||||
fs.mkdirpSync(configDir);
|
||||
}
|
||||
}
|
||||
|
||||
if (!fs.existsSync(path.join(this.config_dir, "gui"))) {
|
||||
|
@ -96,7 +107,7 @@ export class Backend {
|
|||
net_type: "mainnet"
|
||||
},
|
||||
wallet: {
|
||||
rpc_bind_port: 18082,
|
||||
rpc_bind_port: 22026,
|
||||
log_level: 0
|
||||
}
|
||||
};
|
||||
|
@ -111,19 +122,19 @@ export class Backend {
|
|||
|
||||
this.remotes = [
|
||||
{
|
||||
host: "imaginary.stream",
|
||||
host: "public-na.optf.ngo",
|
||||
port: "22023"
|
||||
},
|
||||
{
|
||||
host: "nodes.hashvault.pro",
|
||||
port: "22023"
|
||||
},
|
||||
{
|
||||
host: "explorer.loki.aussie-pools.com",
|
||||
host: "explorer.oxen.aussie-pools.com",
|
||||
port: "18081"
|
||||
},
|
||||
{
|
||||
host: "public.loki.foundation",
|
||||
host: "public-eu.optf.ngo",
|
||||
port: "22023"
|
||||
},
|
||||
{
|
||||
host: "oxen-rpc.caliban.org",
|
||||
port: "22023"
|
||||
}
|
||||
];
|
||||
|
@ -277,14 +288,14 @@ export class Backend {
|
|||
if (params.type === "tx") {
|
||||
path = "tx";
|
||||
} else if (params.type === "service_node") {
|
||||
path = "service_node";
|
||||
path = "sn";
|
||||
}
|
||||
|
||||
if (path) {
|
||||
const baseUrl =
|
||||
net_type === "testnet"
|
||||
? "https://lokitestnet.com"
|
||||
: "https://lokiblocks.com";
|
||||
? "https://testnet.oxen.observer"
|
||||
: "https://oxen.observer";
|
||||
const url = `${baseUrl}/${path}/`;
|
||||
require("electron").shell.openExternal(url + params.id);
|
||||
}
|
||||
|
|
|
@ -29,25 +29,25 @@ export class Daemon {
|
|||
checkVersion() {
|
||||
return new Promise(resolve => {
|
||||
if (process.platform === "win32") {
|
||||
let lokid_path = path.join(__ryo_bin, "lokid.exe");
|
||||
let lokid_version_cmd = `"${lokid_path}" --version`;
|
||||
if (!fs.existsSync(lokid_path)) {
|
||||
let oxend_path = path.join(__ryo_bin, "oxend.exe");
|
||||
let oxend_version_cmd = `"${oxend_path}" --version`;
|
||||
if (!fs.existsSync(oxend_path)) {
|
||||
resolve(false);
|
||||
}
|
||||
child_process.exec(lokid_version_cmd, (error, stdout) => {
|
||||
child_process.exec(oxend_version_cmd, (error, stdout) => {
|
||||
if (error) {
|
||||
resolve(false);
|
||||
}
|
||||
resolve(stdout);
|
||||
});
|
||||
} else {
|
||||
let lokid_path = path.join(__ryo_bin, "lokid");
|
||||
let lokid_version_cmd = `"${lokid_path}" --version`;
|
||||
if (!fs.existsSync(lokid_path)) {
|
||||
let oxend_path = path.join(__ryo_bin, "oxend");
|
||||
let oxend_version_cmd = `"${oxend_path}" --version`;
|
||||
if (!fs.existsSync(oxend_path)) {
|
||||
resolve(false);
|
||||
}
|
||||
child_process.exec(
|
||||
lokid_version_cmd,
|
||||
oxend_version_cmd,
|
||||
{ detached: true },
|
||||
(error, stdout) => {
|
||||
if (error) {
|
||||
|
@ -148,7 +148,7 @@ export class Daemon {
|
|||
args.push("--stagenet");
|
||||
}
|
||||
|
||||
args.push("--log-file", path.join(dirs[net_type], "logs", "lokid.log"));
|
||||
args.push("--log-file", path.join(dirs[net_type], "logs", "oxend.log"));
|
||||
if (daemon.rpc_bind_ip !== "127.0.0.1") {
|
||||
args.push("--confirm-external-bind");
|
||||
}
|
||||
|
@ -173,12 +173,12 @@ export class Daemon {
|
|||
if (status === "closed") {
|
||||
if (process.platform === "win32") {
|
||||
this.daemonProcess = child_process.spawn(
|
||||
path.join(__ryo_bin, "lokid.exe"),
|
||||
path.join(__ryo_bin, "oxend.exe"),
|
||||
args
|
||||
);
|
||||
} else {
|
||||
this.daemonProcess = child_process.spawn(
|
||||
path.join(__ryo_bin, "lokid"),
|
||||
path.join(__ryo_bin, "oxend"),
|
||||
args,
|
||||
{
|
||||
detached: true
|
||||
|
@ -484,14 +484,14 @@ export class Daemon {
|
|||
});
|
||||
}
|
||||
|
||||
async getLNSRecordsForOwners(owners) {
|
||||
async getONSRecordsForOwners(owners) {
|
||||
if (!Array.isArray(owners) || owners.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// only 256 addresses allowed in this call
|
||||
let ownersMax = owners.slice(0, 256);
|
||||
const data = await this.sendRPC("lns_owners_to_names", {
|
||||
const data = await this.sendRPC("ons_owners_to_names", {
|
||||
entries: ownersMax
|
||||
});
|
||||
if (!data.hasOwnProperty("result")) return [];
|
||||
|
@ -506,10 +506,10 @@ export class Daemon {
|
|||
};
|
||||
});
|
||||
|
||||
return this._sanitizeLNSRecords(recordsWithOwners);
|
||||
return this._sanitizeONSRecords(recordsWithOwners);
|
||||
}
|
||||
|
||||
async getLNSRecord(nameHash) {
|
||||
async getONSRecord(nameHash) {
|
||||
if (!nameHash || nameHash.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
@ -519,22 +519,23 @@ export class Daemon {
|
|||
{
|
||||
name_hash: nameHash,
|
||||
// 0 = session
|
||||
// 1 = wallet
|
||||
// 2 = lokinet
|
||||
types: [0, 2]
|
||||
types: [0, 1, 2]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const data = await this.sendRPC("lns_names_to_owners", params);
|
||||
const data = await this.sendRPC("ons_names_to_owners", params);
|
||||
if (!data.hasOwnProperty("result")) return null;
|
||||
|
||||
const entries = this._sanitizeLNSRecords(data.result.entries);
|
||||
const entries = this._sanitizeONSRecords(data.result.entries);
|
||||
if (entries.length === 0) return null;
|
||||
|
||||
return entries[0];
|
||||
}
|
||||
|
||||
_sanitizeLNSRecords(records) {
|
||||
_sanitizeONSRecords(records) {
|
||||
return (records || []).map(record => {
|
||||
// Record type is in uint16 format
|
||||
// Session = 0
|
||||
|
@ -543,6 +544,9 @@ export class Daemon {
|
|||
if (record.type === 0) {
|
||||
type = "session";
|
||||
}
|
||||
if (record.type === 1) {
|
||||
type = "wallet";
|
||||
}
|
||||
return {
|
||||
...record,
|
||||
type
|
||||
|
|
|
@ -18,14 +18,16 @@ export class WalletRPC {
|
|||
this.id = 0;
|
||||
this.net_type = "mainnet";
|
||||
this.heartbeat = null;
|
||||
this.lnsHeartbeat = null;
|
||||
this.onsHeartbeat = null;
|
||||
this.wallet_state = {
|
||||
open: false,
|
||||
name: "",
|
||||
password_hash: null,
|
||||
balance: null,
|
||||
unlocked_balance: null,
|
||||
lnsRecords: []
|
||||
accrued_balance: null,
|
||||
accrued_balance_next_payout: null,
|
||||
onsRecords: []
|
||||
};
|
||||
this.isRPCSyncing = false;
|
||||
this.dirs = null;
|
||||
|
@ -89,6 +91,8 @@ export class WalletRPC {
|
|||
options.wallet.rpc_bind_port,
|
||||
"--daemon-address",
|
||||
daemon_address,
|
||||
"--rpc-bind-ip",
|
||||
"127.0.0.1",
|
||||
"--log-level",
|
||||
options.wallet.log_level
|
||||
];
|
||||
|
@ -135,8 +139,8 @@ export class WalletRPC {
|
|||
|
||||
const rpcExecutable =
|
||||
process.platform === "win32"
|
||||
? "loki-wallet-rpc.exe"
|
||||
: "loki-wallet-rpc";
|
||||
? "oxen-wallet-rpc.exe"
|
||||
: "oxen-wallet-rpc";
|
||||
// eslint-disable-next-line no-undef
|
||||
const rpcPath = path.join(__ryo_bin, rpcExecutable);
|
||||
|
||||
|
@ -144,7 +148,7 @@ export class WalletRPC {
|
|||
if (!fs.existsSync(rpcPath)) {
|
||||
reject(
|
||||
new Error(
|
||||
"Failed to find Loki Wallet RPC. Please make sure you anti-virus has not removed it."
|
||||
"Failed to find Oxen Wallet RPC. Please make sure your anti-virus has not removed it."
|
||||
)
|
||||
);
|
||||
return;
|
||||
|
@ -251,7 +255,7 @@ export class WalletRPC {
|
|||
break;
|
||||
|
||||
case "decrypt_record": {
|
||||
const record = await this.decryptLNSRecord(params.type, params.name);
|
||||
const record = await this.decryptONSRecord(params.type, params.name);
|
||||
this.sendGateway("set_decrypt_record_result", {
|
||||
record,
|
||||
decrypted: !!record
|
||||
|
@ -268,7 +272,12 @@ export class WalletRPC {
|
|||
break;
|
||||
|
||||
case "create_wallet":
|
||||
this.createWallet(params.name, params.password, params.language);
|
||||
this.createWallet(
|
||||
params.name,
|
||||
params.password,
|
||||
params.language,
|
||||
params.hardware_wallet
|
||||
);
|
||||
break;
|
||||
|
||||
case "restore_wallet":
|
||||
|
@ -284,7 +293,7 @@ export class WalletRPC {
|
|||
break;
|
||||
|
||||
case "restore_view_wallet":
|
||||
// TODO: Decide if we want this for loki
|
||||
// TODO: Decide if we want this for Oxen
|
||||
this.restoreViewWallet(
|
||||
params.name,
|
||||
params.password,
|
||||
|
@ -351,8 +360,8 @@ export class WalletRPC {
|
|||
!!params.isSweepAll
|
||||
);
|
||||
break;
|
||||
case "purchase_lns":
|
||||
this.purchaseLNS(
|
||||
case "purchase_ons":
|
||||
this.purchaseONS(
|
||||
params.password,
|
||||
params.type,
|
||||
params.name,
|
||||
|
@ -361,11 +370,11 @@ export class WalletRPC {
|
|||
params.backup_owner || ""
|
||||
);
|
||||
break;
|
||||
case "lns_renew_mapping":
|
||||
this.lnsRenewMapping(params.password, params.type, params.name);
|
||||
case "ons_renew_mapping":
|
||||
this.onsRenewMapping(params.password, params.type, params.name);
|
||||
break;
|
||||
case "update_lns_mapping":
|
||||
this.updateLNSMapping(
|
||||
case "update_ons_mapping":
|
||||
this.updateONSMapping(
|
||||
params.password,
|
||||
params.type,
|
||||
params.name,
|
||||
|
@ -388,6 +397,14 @@ export class WalletRPC {
|
|||
);
|
||||
break;
|
||||
|
||||
case "sign":
|
||||
this.sign(params.data);
|
||||
break;
|
||||
|
||||
case "verify":
|
||||
this.verify(params.data, params.address, params.signature);
|
||||
break;
|
||||
|
||||
case "add_address_book":
|
||||
this.addAddressBook(
|
||||
params.address,
|
||||
|
@ -423,6 +440,9 @@ export class WalletRPC {
|
|||
case "import_key_images":
|
||||
this.importKeyImages(params.password, params.path);
|
||||
break;
|
||||
case "export_transfers":
|
||||
this.exportTransfers(params.password, params.path);
|
||||
break;
|
||||
|
||||
case "change_wallet_password":
|
||||
this.changeWalletPassword(params.old_password, params.new_password);
|
||||
|
@ -494,13 +514,20 @@ export class WalletRPC {
|
|||
});
|
||||
}
|
||||
|
||||
createWallet(filename, password, language) {
|
||||
isHardwareWallet(filename) {
|
||||
let hwfile = path.join(this.wallet_dir, filename + ".hwdev.txt");
|
||||
return fs.existsSync(hwfile);
|
||||
}
|
||||
|
||||
createWallet(filename, password, language, hardware_wallet) {
|
||||
// Reset the status error
|
||||
this.sendGateway("reset_wallet_error");
|
||||
this.sendRPC("create_wallet", {
|
||||
filename,
|
||||
password,
|
||||
language
|
||||
language,
|
||||
hardware_wallet: !!hardware_wallet,
|
||||
device_label: hardware_wallet ? "hardware_wallet" : undefined
|
||||
}).then(data => {
|
||||
if (data.hasOwnProperty("error")) {
|
||||
this.sendGateway("set_wallet_error", { status: data.error });
|
||||
|
@ -687,6 +714,14 @@ export class WalletRPC {
|
|||
errorOnExist: true
|
||||
});
|
||||
}
|
||||
|
||||
if (fs.existsSync(import_path + ".hwdev.txt")) {
|
||||
fs.copySync(
|
||||
import_path + ".hwdev.txt",
|
||||
destination + ".hwdev.txt",
|
||||
fs.constants.COPYFILE_EXCL
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
this.sendGateway("set_wallet_error", {
|
||||
status: {
|
||||
|
@ -744,6 +779,8 @@ export class WalletRPC {
|
|||
address: "",
|
||||
balance: 0,
|
||||
unlocked_balance: 0,
|
||||
accrued_balance: 0,
|
||||
accrued_balance_next_payout: 0,
|
||||
height: 0,
|
||||
view_only: false
|
||||
},
|
||||
|
@ -764,6 +801,9 @@ export class WalletRPC {
|
|||
} else if (n.method == "getbalance") {
|
||||
wallet.info.balance = n.result.balance;
|
||||
wallet.info.unlocked_balance = n.result.unlocked_balance;
|
||||
wallet.info.accrued_balance = n.result.accrued_balance;
|
||||
wallet.info.accrued_balance_next_payout =
|
||||
n.result.accrued_balance_next_payout;
|
||||
} else if (n.method == "query_key") {
|
||||
wallet.secret[n.params.key_type] = n.result.key;
|
||||
if (n.params.key_type == "spend_key") {
|
||||
|
@ -774,6 +814,10 @@ export class WalletRPC {
|
|||
}
|
||||
}
|
||||
|
||||
if (this.isHardwareWallet(filename)) {
|
||||
wallet.info.hardware_wallet = true;
|
||||
}
|
||||
|
||||
this.saveWallet().then(() => {
|
||||
let address_txt_path = path.join(
|
||||
this.wallet_dir,
|
||||
|
@ -790,7 +834,11 @@ export class WalletRPC {
|
|||
|
||||
this.sendGateway("set_wallet_data", wallet);
|
||||
|
||||
this.startHeartbeat();
|
||||
if (this.isHardwareWallet(filename)) {
|
||||
this.startHeartbeat(10);
|
||||
} else {
|
||||
this.startHeartbeat();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -820,6 +868,12 @@ export class WalletRPC {
|
|||
});
|
||||
}
|
||||
|
||||
const hardware_wallet_file = path.join(
|
||||
this.wallet_dir,
|
||||
filename + ".hwdev.txt"
|
||||
);
|
||||
const hardware_wallet = fs.existsSync(hardware_wallet_file);
|
||||
|
||||
// store hash of the password so we can check against it later when requesting private keys, or for sending txs
|
||||
this.wallet_state.password_hash = crypto
|
||||
.pbkdf2Sync(password, this.auth[2], 1000, 64, "sha512")
|
||||
|
@ -827,10 +881,20 @@ export class WalletRPC {
|
|||
this.wallet_state.name = filename;
|
||||
this.wallet_state.open = true;
|
||||
|
||||
this.startHeartbeat();
|
||||
if (hardware_wallet) {
|
||||
this.startHeartbeat(10);
|
||||
} else {
|
||||
this.startHeartbeat();
|
||||
}
|
||||
|
||||
this.purchasedNames = {};
|
||||
|
||||
this.sendGateway("set_wallet_data", {
|
||||
info: {
|
||||
hardware_wallet
|
||||
}
|
||||
});
|
||||
|
||||
// Check if we have a view only wallet by querying the spend key
|
||||
this.sendRPC("query_key", { key_type: "spend_key" }).then(data => {
|
||||
if (data.hasOwnProperty("error") || !data.hasOwnProperty("result")) {
|
||||
|
@ -847,18 +911,18 @@ export class WalletRPC {
|
|||
});
|
||||
}
|
||||
|
||||
startHeartbeat() {
|
||||
startHeartbeat(multiplier = 1) {
|
||||
clearInterval(this.heartbeat);
|
||||
this.heartbeat = setInterval(() => {
|
||||
this.heartbeatAction();
|
||||
}, 5000);
|
||||
}, 5000 * multiplier);
|
||||
this.heartbeatAction(true);
|
||||
|
||||
clearInterval(this.lnsHeartbeat);
|
||||
this.lnsHeartbeat = setInterval(() => {
|
||||
this.updateLocalLNSRecords();
|
||||
}, 30 * 1000); // Every 30 seconds
|
||||
this.updateLocalLNSRecords();
|
||||
clearInterval(this.onsHeartbeat);
|
||||
this.onsHeartbeat = setInterval(() => {
|
||||
this.updateLocalONSRecords();
|
||||
}, 30 * 1000 * multiplier); // Every 30 seconds
|
||||
this.updateLocalONSRecords();
|
||||
}
|
||||
|
||||
heartbeatAction(extended = false) {
|
||||
|
@ -915,7 +979,10 @@ export class WalletRPC {
|
|||
} else if (n.method == "getbalance") {
|
||||
if (
|
||||
this.wallet_state.balance == n.result.balance &&
|
||||
this.wallet_state.unlocked_balance == n.result.unlocked_balance
|
||||
this.wallet_state.unlocked_balance == n.result.unlocked_balance &&
|
||||
this.wallet_state.accrued_balance == n.result.accrued_balance &&
|
||||
this.wallet_state.accrued_balance_next_payout ==
|
||||
n.result.accrued_balance_next_payout
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
@ -923,6 +990,10 @@ export class WalletRPC {
|
|||
this.wallet_state.balance = wallet.info.balance = n.result.balance;
|
||||
this.wallet_state.unlocked_balance = wallet.info.unlocked_balance =
|
||||
n.result.unlocked_balance;
|
||||
this.wallet_state.accrued_balance = wallet.info.accrued_balance =
|
||||
n.result.accrued_balance;
|
||||
this.wallet_state.accrued_balance_next_payout = wallet.info.accrued_balance_next_payout =
|
||||
n.result.accrued_balance_next_payout;
|
||||
this.sendGateway("set_wallet_data", {
|
||||
info: wallet.info
|
||||
});
|
||||
|
@ -959,7 +1030,7 @@ export class WalletRPC {
|
|||
});
|
||||
}
|
||||
|
||||
async updateLocalLNSRecords() {
|
||||
async updateLocalONSRecords() {
|
||||
try {
|
||||
const addressData = await this.sendRPC(
|
||||
"get_address",
|
||||
|
@ -978,12 +1049,12 @@ export class WalletRPC {
|
|||
const addresses = results.map(a => a.address).filter(a => !!a);
|
||||
if (addresses.length === 0) return;
|
||||
|
||||
const records = await this.backend.daemon.getLNSRecordsForOwners(
|
||||
const records = await this.backend.daemon.getONSRecordsForOwners(
|
||||
addresses
|
||||
);
|
||||
|
||||
// We need to ensure that we decrypt any incoming records that we already have
|
||||
const currentRecords = this.wallet_state.lnsRecords;
|
||||
const currentRecords = this.wallet_state.onsRecords;
|
||||
const recordsToUpdate = { ...this.purchasedNames };
|
||||
const newRecords = records.map(record => {
|
||||
// If we have a new record or we haven't decrypted our current record then we should return the new record
|
||||
|
@ -1013,13 +1084,13 @@ export class WalletRPC {
|
|||
};
|
||||
});
|
||||
|
||||
this.wallet_state.lnsRecords = newRecords;
|
||||
this.wallet_state.onsRecords = newRecords;
|
||||
|
||||
// fetch the known (cached) records from the wallet and add the data
|
||||
// to the records being set in state
|
||||
let known_names = await this.lnsKnownNames();
|
||||
let known_names = await this.onsKnownNames();
|
||||
|
||||
// Fill the necessary decrypted values of the cached LNS names
|
||||
// Fill the necessary decrypted values of the cached ONS names
|
||||
for (let r of newRecords) {
|
||||
for (let k of known_names) {
|
||||
if (k.hashed === r.name_hash) {
|
||||
|
@ -1030,31 +1101,31 @@ export class WalletRPC {
|
|||
}
|
||||
}
|
||||
|
||||
this.sendGateway("set_wallet_data", { lnsRecords: newRecords });
|
||||
this.sendGateway("set_wallet_data", { onsRecords: newRecords });
|
||||
|
||||
// Decrypt the records serially
|
||||
let updatePromise = Promise.resolve();
|
||||
for (const [name, type] of Object.entries(recordsToUpdate)) {
|
||||
updatePromise = updatePromise.then(() => {
|
||||
this.decryptLNSRecord(type, name);
|
||||
this.decryptONSRecord(type, name);
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.debug("Something went wrong when updating lns records: ", e);
|
||||
console.debug("Something went wrong when updating ons records: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Get the LNS records cached in this wallet.
|
||||
Get the ONS records cached in this wallet.
|
||||
*/
|
||||
async lnsKnownNames() {
|
||||
async onsKnownNames() {
|
||||
try {
|
||||
let params = {
|
||||
decrypt: true,
|
||||
include_expired: false
|
||||
};
|
||||
|
||||
let data = await this.sendRPC("lns_known_names", params);
|
||||
let data = await this.sendRPC("ons_known_names", params);
|
||||
|
||||
if (data.result && data.result.known_names) {
|
||||
return data.result.known_names;
|
||||
|
@ -1068,11 +1139,11 @@ export class WalletRPC {
|
|||
}
|
||||
|
||||
/*
|
||||
Renews an LNS (Lokinet) mapping, since they can expire
|
||||
Renews an ONS (Lokinet) mapping, since they can expire
|
||||
type can be:
|
||||
lokinet_1y, lokinet_2y, lokinet_5y, lokinet_10y
|
||||
*/
|
||||
lnsRenewMapping(password, type, name) {
|
||||
onsRenewMapping(password, type, name) {
|
||||
let _name = name.trim().toLowerCase();
|
||||
|
||||
// the RPC accepts names with the .loki already appeneded only
|
||||
|
@ -1089,7 +1160,7 @@ export class WalletRPC {
|
|||
"sha512",
|
||||
(err, password_hash) => {
|
||||
if (err) {
|
||||
this.sendGateway("set_lns_status", {
|
||||
this.sendGateway("set_ons_status", {
|
||||
code: -1,
|
||||
i18n: "notification.errors.internalError",
|
||||
sending: false
|
||||
|
@ -1097,7 +1168,7 @@ export class WalletRPC {
|
|||
return;
|
||||
}
|
||||
if (!this.isValidPasswordHash(password_hash)) {
|
||||
this.sendGateway("set_lns_status", {
|
||||
this.sendGateway("set_ons_status", {
|
||||
code: -1,
|
||||
i18n: "notification.errors.invalidPassword",
|
||||
sending: false
|
||||
|
@ -1110,12 +1181,12 @@ export class WalletRPC {
|
|||
name: _name
|
||||
};
|
||||
|
||||
this.sendRPC("lns_renew_mapping", params).then(data => {
|
||||
this.sendRPC("ons_renew_mapping", params).then(data => {
|
||||
if (data.hasOwnProperty("error")) {
|
||||
let error =
|
||||
data.error.message.charAt(0).toUpperCase() +
|
||||
data.error.message.slice(1);
|
||||
this.sendGateway("set_lns_status", {
|
||||
this.sendGateway("set_ons_status", {
|
||||
code: -1,
|
||||
message: error,
|
||||
sending: false
|
||||
|
@ -1125,9 +1196,9 @@ export class WalletRPC {
|
|||
|
||||
this.purchasedNames[name.trim()] = type;
|
||||
|
||||
setTimeout(() => this.updateLocalLNSRecords(), 5000);
|
||||
setTimeout(() => this.updateLocalONSRecords(), 5000);
|
||||
|
||||
this.sendGateway("set_lns_status", {
|
||||
this.sendGateway("set_ons_status", {
|
||||
code: 0,
|
||||
i18n: "notification.positive.nameRenewed",
|
||||
sending: false
|
||||
|
@ -1138,21 +1209,21 @@ export class WalletRPC {
|
|||
}
|
||||
|
||||
/*
|
||||
Get our LNS record and update our wallet state with decrypted values.
|
||||
Get our ONS record and update our wallet state with decrypted values.
|
||||
This will return `null` if the record is not in our currently stored records.
|
||||
*/
|
||||
async decryptLNSRecord(type, name) {
|
||||
async decryptONSRecord(type, name) {
|
||||
let _type = type;
|
||||
// type can initially be "lokinet_1y" etc. on a purchase
|
||||
if (type.startsWith("lokinet")) {
|
||||
_type = "lokinet";
|
||||
}
|
||||
try {
|
||||
const record = await this.getLNSRecord(_type, name);
|
||||
const record = await this.getONSRecord(_type, name);
|
||||
if (!record) return null;
|
||||
|
||||
// Update our current records with the new decrypted record
|
||||
const currentRecords = this.wallet_state.lnsRecords;
|
||||
const currentRecords = this.wallet_state.onsRecords;
|
||||
const isOurRecord = currentRecords.find(
|
||||
c => c.name_hash === record.name_hash
|
||||
);
|
||||
|
@ -1167,7 +1238,7 @@ export class WalletRPC {
|
|||
const params = {
|
||||
names: [_record]
|
||||
};
|
||||
this.sendRPC("lns_add_known_names", params);
|
||||
this.sendRPC("ons_add_known_names", params);
|
||||
}
|
||||
|
||||
const newRecords = currentRecords.map(current => {
|
||||
|
@ -1176,21 +1247,21 @@ export class WalletRPC {
|
|||
}
|
||||
return current;
|
||||
});
|
||||
this.wallet_state.lnsRecords = newRecords;
|
||||
this.sendGateway("set_wallet_data", { lnsRecords: newRecords });
|
||||
this.wallet_state.onsRecords = newRecords;
|
||||
this.sendGateway("set_wallet_data", { onsRecords: newRecords });
|
||||
return record;
|
||||
} catch (e) {
|
||||
console.debug("Something went wrong decrypting lns record: ", e);
|
||||
console.debug("Something went wrong decrypting ons record: ", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Get a LNS record associated with the given name
|
||||
Get a ONS record associated with the given name
|
||||
*/
|
||||
async getLNSRecord(type, name) {
|
||||
// We currently only support session and lokinet
|
||||
const types = ["session", "lokinet"];
|
||||
async getONSRecord(type, name) {
|
||||
// We support session, wallet and lokinet
|
||||
const types = ["session", "wallet", "lokinet"];
|
||||
if (!types.includes(type)) return null;
|
||||
|
||||
if (!name || name.trim().length === 0) return null;
|
||||
|
@ -1202,14 +1273,14 @@ export class WalletRPC {
|
|||
fullName = fullName + ".loki";
|
||||
}
|
||||
|
||||
const nameHash = await this.hashLNSName(type, lowerCaseName);
|
||||
const nameHash = await this.hashONSName(type, lowerCaseName);
|
||||
if (!nameHash) return null;
|
||||
|
||||
const record = await this.backend.daemon.getLNSRecord(nameHash);
|
||||
const record = await this.backend.daemon.getONSRecord(nameHash);
|
||||
if (!record || !record.encrypted_value) return null;
|
||||
|
||||
// Decrypt the value if possible
|
||||
const value = await this.decryptLNSValue(
|
||||
const value = await this.decryptONSValue(
|
||||
type,
|
||||
fullName,
|
||||
record.encrypted_value
|
||||
|
@ -1222,7 +1293,7 @@ export class WalletRPC {
|
|||
};
|
||||
}
|
||||
|
||||
async hashLNSName(type, name) {
|
||||
async hashONSName(type, name) {
|
||||
if (!type || !name) return null;
|
||||
|
||||
let fullName = name;
|
||||
|
@ -1231,7 +1302,7 @@ export class WalletRPC {
|
|||
}
|
||||
|
||||
try {
|
||||
const data = await this.sendRPC("lns_hash_name", {
|
||||
const data = await this.sendRPC("ons_hash_name", {
|
||||
type,
|
||||
name: fullName
|
||||
});
|
||||
|
@ -1245,12 +1316,12 @@ export class WalletRPC {
|
|||
|
||||
return (data.result && data.result.name) || null;
|
||||
} catch (e) {
|
||||
console.debug("Failed to hash lns name: ", e);
|
||||
console.debug("Failed to hash ons name: ", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async decryptLNSValue(type, name, encrypted_value) {
|
||||
async decryptONSValue(type, name, encrypted_value) {
|
||||
if (!type || !name || !encrypted_value) return null;
|
||||
|
||||
let fullName = name;
|
||||
|
@ -1259,7 +1330,7 @@ export class WalletRPC {
|
|||
}
|
||||
|
||||
try {
|
||||
const data = await this.sendRPC("lns_decrypt_value", {
|
||||
const data = await this.sendRPC("ons_decrypt_value", {
|
||||
type,
|
||||
name: fullName,
|
||||
encrypted_value
|
||||
|
@ -1274,11 +1345,109 @@ export class WalletRPC {
|
|||
|
||||
return (data.result && data.result.value) || null;
|
||||
} catch (e) {
|
||||
console.debug("Failed to decrypt lns value: ", e);
|
||||
console.debug("Failed to decrypt ons value: ", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async sign(data) {
|
||||
// set to loading
|
||||
this.sendGateway("set_sign_status", {
|
||||
code: 0,
|
||||
sending: true
|
||||
});
|
||||
try {
|
||||
const rpcData = await this.sendRPC("sign", { data });
|
||||
if (
|
||||
!rpcData ||
|
||||
rpcData.hasOwnProperty("error") ||
|
||||
!rpcData.hasOwnProperty("result")
|
||||
) {
|
||||
const error = rpcData?.error?.message || "Unknown error";
|
||||
this.sendGateway("set_sign_status", {
|
||||
code: -1,
|
||||
message: error,
|
||||
sending: false
|
||||
});
|
||||
return;
|
||||
}
|
||||
const signature = rpcData.result.signature;
|
||||
|
||||
this.sendGateway("set_sign_status", {
|
||||
code: 1,
|
||||
sending: false,
|
||||
signature: signature
|
||||
});
|
||||
return;
|
||||
} catch (err) {
|
||||
console.debug(`Failed to sign data: ${data} with error: ${err}`);
|
||||
this.sendGateway("set_sign_status", {
|
||||
code: -1,
|
||||
message: err,
|
||||
sending: false
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async verify(data, address, signature) {
|
||||
this.sendGateway("set_verify_status", {
|
||||
code: 0,
|
||||
sending: true
|
||||
});
|
||||
try {
|
||||
const rpcData = await this.sendRPC("verify", {
|
||||
data,
|
||||
address,
|
||||
signature
|
||||
});
|
||||
if (
|
||||
!rpcData ||
|
||||
rpcData.hasOwnProperty("error") ||
|
||||
!rpcData.hasOwnProperty("result")
|
||||
) {
|
||||
let errorI18n = "";
|
||||
const error = rpcData.error.message || "Unknown error";
|
||||
if (error && error.includes("Invalid address")) {
|
||||
errorI18n = "notification.errors.invalidAddress";
|
||||
}
|
||||
this.sendGateway("set_verify_status", {
|
||||
code: -1,
|
||||
message: "",
|
||||
i18n: errorI18n || "Unknown error",
|
||||
sending: false
|
||||
});
|
||||
return;
|
||||
}
|
||||
const good = rpcData.result.good;
|
||||
if (good) {
|
||||
// success
|
||||
this.sendGateway("set_verify_status", {
|
||||
code: 1,
|
||||
sending: false,
|
||||
i18n: "notification.positive.signatureVerified",
|
||||
message: ""
|
||||
});
|
||||
} else {
|
||||
// error
|
||||
this.sendGateway("set_verify_status", {
|
||||
code: -1,
|
||||
sending: false,
|
||||
i18n: "notification.errors.invalidSignature",
|
||||
message: ""
|
||||
});
|
||||
}
|
||||
|
||||
return;
|
||||
} catch (err) {
|
||||
this.sendGateway("set_verify_status", {
|
||||
code: -1,
|
||||
message: err.toString(),
|
||||
i18n: "",
|
||||
sending: false
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
stake(password, amount, service_node_key, destination) {
|
||||
crypto.pbkdf2(
|
||||
password,
|
||||
|
@ -1576,6 +1745,9 @@ export class WalletRPC {
|
|||
// send address and tx fees before sending
|
||||
// isSweepAll refers to if it's the sweep from service nodes page
|
||||
transfer(password, amount, address, priority, isSweepAll) {
|
||||
console.log(
|
||||
"TODO sean remove this - wallet: " + JSON.stringify(this.wallet)
|
||||
);
|
||||
const cryptoCallback = (err, password_hash) => {
|
||||
if (err) {
|
||||
this.sendGateway("set_tx_status", {
|
||||
|
@ -1676,7 +1848,7 @@ export class WalletRPC {
|
|||
crypto.pbkdf2(password, this.auth[2], 1000, 64, "sha512", cryptoCallback);
|
||||
}
|
||||
|
||||
purchaseLNS(password, type, name, value, owner, backupOwner) {
|
||||
purchaseONS(password, type, name, value, owner, backupOwner) {
|
||||
let _name = name.trim().toLowerCase();
|
||||
const _owner = owner.trim() === "" ? null : owner;
|
||||
const backup_owner = backupOwner.trim() === "" ? null : backupOwner;
|
||||
|
@ -1696,7 +1868,7 @@ export class WalletRPC {
|
|||
"sha512",
|
||||
(err, password_hash) => {
|
||||
if (err) {
|
||||
this.sendGateway("set_lns_status", {
|
||||
this.sendGateway("set_ons_status", {
|
||||
code: -1,
|
||||
i18n: "notification.errors.internalError",
|
||||
sending: false
|
||||
|
@ -1704,7 +1876,7 @@ export class WalletRPC {
|
|||
return;
|
||||
}
|
||||
if (!this.isValidPasswordHash(password_hash)) {
|
||||
this.sendGateway("set_lns_status", {
|
||||
this.sendGateway("set_ons_status", {
|
||||
code: -1,
|
||||
i18n: "notification.errors.invalidPassword",
|
||||
sending: false
|
||||
|
@ -1720,12 +1892,12 @@ export class WalletRPC {
|
|||
value
|
||||
};
|
||||
|
||||
this.sendRPC("lns_buy_mapping", params).then(data => {
|
||||
this.sendRPC("ons_buy_mapping", params).then(data => {
|
||||
if (data.hasOwnProperty("error")) {
|
||||
let error =
|
||||
data.error.message.charAt(0).toUpperCase() +
|
||||
data.error.message.slice(1);
|
||||
this.sendGateway("set_lns_status", {
|
||||
this.sendGateway("set_ons_status", {
|
||||
code: -1,
|
||||
message: error,
|
||||
sending: false
|
||||
|
@ -1736,9 +1908,9 @@ export class WalletRPC {
|
|||
this.purchasedNames[name.trim()] = type;
|
||||
|
||||
// Fetch new records and then get the decrypted record for the one we just inserted
|
||||
setTimeout(() => this.updateLocalLNSRecords(), 5000);
|
||||
setTimeout(() => this.updateLocalONSRecords(), 5000);
|
||||
|
||||
this.sendGateway("set_lns_status", {
|
||||
this.sendGateway("set_ons_status", {
|
||||
code: 0,
|
||||
i18n: "notification.positive.namePurchased",
|
||||
sending: false
|
||||
|
@ -1748,7 +1920,7 @@ export class WalletRPC {
|
|||
);
|
||||
}
|
||||
|
||||
updateLNSMapping(password, type, name, value, owner, backupOwner) {
|
||||
updateONSMapping(password, type, name, value, owner, backupOwner) {
|
||||
let _name = name.trim().toLowerCase();
|
||||
const _owner = owner.trim() === "" ? null : owner;
|
||||
const backup_owner = backupOwner.trim() === "" ? null : backupOwner;
|
||||
|
@ -1768,7 +1940,7 @@ export class WalletRPC {
|
|||
"sha512",
|
||||
(err, password_hash) => {
|
||||
if (err) {
|
||||
this.sendGateway("set_lns_status", {
|
||||
this.sendGateway("set_ons_status", {
|
||||
code: -1,
|
||||
i18n: "notification.errors.internalError",
|
||||
sending: false
|
||||
|
@ -1776,7 +1948,7 @@ export class WalletRPC {
|
|||
return;
|
||||
}
|
||||
if (!this.isValidPasswordHash(password_hash)) {
|
||||
this.sendGateway("set_lns_status", {
|
||||
this.sendGateway("set_ons_status", {
|
||||
code: -1,
|
||||
i18n: "notification.errors.invalidPassword",
|
||||
sending: false
|
||||
|
@ -1792,12 +1964,12 @@ export class WalletRPC {
|
|||
value
|
||||
};
|
||||
|
||||
this.sendRPC("lns_update_mapping", params).then(data => {
|
||||
this.sendRPC("ons_update_mapping", params).then(data => {
|
||||
if (data.hasOwnProperty("error")) {
|
||||
let error =
|
||||
data.error.message.charAt(0).toUpperCase() +
|
||||
data.error.message.slice(1);
|
||||
this.sendGateway("set_lns_status", {
|
||||
this.sendGateway("set_ons_status", {
|
||||
code: -1,
|
||||
message: error,
|
||||
sending: false
|
||||
|
@ -1808,11 +1980,11 @@ export class WalletRPC {
|
|||
this.purchasedNames[name.trim()] = type;
|
||||
|
||||
// Fetch new records and then get the decrypted record for the one we just inserted
|
||||
setTimeout(() => this.updateLocalLNSRecords(), 5000);
|
||||
setTimeout(() => this.updateLocalONSRecords(), 5000);
|
||||
|
||||
// Optimistically update our record
|
||||
const { lnsRecords } = this.wallet_state;
|
||||
const newRecords = lnsRecords.map(record => {
|
||||
const { onsRecords } = this.wallet_state;
|
||||
const newRecords = onsRecords.map(record => {
|
||||
if (
|
||||
record.type === type &&
|
||||
record.name &&
|
||||
|
@ -1828,12 +2000,12 @@ export class WalletRPC {
|
|||
|
||||
return record;
|
||||
});
|
||||
this.wallet_state.lnsRecords = newRecords;
|
||||
this.sendGateway("set_wallet_data", { lnsRecords: newRecords });
|
||||
this.wallet_state.onsRecords = newRecords;
|
||||
this.sendGateway("set_wallet_data", { onsRecords: newRecords });
|
||||
|
||||
this.sendGateway("set_lns_status", {
|
||||
this.sendGateway("set_ons_status", {
|
||||
code: 0,
|
||||
i18n: "notification.positive.lnsRecordUpdated",
|
||||
i18n: "notification.positive.onsRecordUpdated",
|
||||
sending: false
|
||||
});
|
||||
});
|
||||
|
@ -2004,7 +2176,10 @@ export class WalletRPC {
|
|||
info: {
|
||||
address: data[0].result.address,
|
||||
balance: data[1].result.balance,
|
||||
unlocked_balance: data[1].result.unlocked_balance
|
||||
unlocked_balance: data[1].result.unlocked_balance,
|
||||
accrued_balance: data[1].result.accrued_balance,
|
||||
accrued_balance_next_payout:
|
||||
data[1].result.accrued_balance_next_payout
|
||||
// num_unspent_outputs: data[1].result.num_unspent_outputs
|
||||
},
|
||||
address_list: {
|
||||
|
@ -2362,6 +2537,79 @@ export class WalletRPC {
|
|||
);
|
||||
}
|
||||
|
||||
exportTransfers(password, filename = null) {
|
||||
crypto.pbkdf2(
|
||||
password,
|
||||
this.auth[2],
|
||||
1000,
|
||||
64,
|
||||
"sha512",
|
||||
(err, password_hash) => {
|
||||
if (err) {
|
||||
this.sendGateway("show_notification", {
|
||||
type: "negative",
|
||||
i18n: "notification.errors.internalError",
|
||||
timeout: 2000
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!this.isValidPasswordHash(password_hash)) {
|
||||
this.sendGateway("show_notification", {
|
||||
type: "negative",
|
||||
i18n: "notification.errors.invalidPassword",
|
||||
timeout: 2000
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (filename == null) {
|
||||
filename = path.join(
|
||||
this.wallet_data_dir,
|
||||
"CSV",
|
||||
this.wallet_state.name,
|
||||
"transfers.csv"
|
||||
);
|
||||
} else {
|
||||
filename = path.join(filename, "transfers.csv");
|
||||
}
|
||||
|
||||
const onError = () =>
|
||||
this.sendGateway("show_notification", {
|
||||
type: "negative",
|
||||
i18n: "notification.errors.exportTransfers",
|
||||
timeout: 2000
|
||||
});
|
||||
|
||||
this.sendRPC("export_transfers")
|
||||
.then(data => {
|
||||
if (
|
||||
data.hasOwnProperty("error") ||
|
||||
!data.hasOwnProperty("result")
|
||||
) {
|
||||
onError();
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.result.data) {
|
||||
fs.outputFileSync(filename, data.result.data);
|
||||
this.sendGateway("show_notification", {
|
||||
i18n: ["notification.positive.exportTransfers", { filename }],
|
||||
timeout: 2000
|
||||
});
|
||||
} else {
|
||||
this.sendGateway("show_notification", {
|
||||
type: "warning",
|
||||
textColor: "black",
|
||||
i18n: "notification.warnings.noExportTransfers",
|
||||
timeout: 2000
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(onError);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
copyOldGuiWallets(wallets) {
|
||||
this.sendGateway("set_old_gui_import_status", {
|
||||
code: 1,
|
||||
|
@ -2481,7 +2729,7 @@ export class WalletRPC {
|
|||
return;
|
||||
}
|
||||
|
||||
// Exclude all files without a keys extension
|
||||
// Exclude all files without keys
|
||||
if (path.extname(filename) !== ".keys") return;
|
||||
|
||||
const wallet_name = path.parse(filename).name;
|
||||
|
@ -2490,7 +2738,8 @@ export class WalletRPC {
|
|||
let wallet_data = {
|
||||
name: wallet_name,
|
||||
address: null,
|
||||
password_protected: null
|
||||
password_protected: null,
|
||||
hardware_wallet: false
|
||||
};
|
||||
|
||||
if (
|
||||
|
@ -2519,6 +2768,12 @@ export class WalletRPC {
|
|||
}
|
||||
}
|
||||
|
||||
if (
|
||||
fs.existsSync(path.join(this.wallet_dir, wallet_name + ".hwdev.txt"))
|
||||
) {
|
||||
wallet_data.hardware_wallet = true;
|
||||
}
|
||||
|
||||
wallets.list.push(wallet_data);
|
||||
} catch (e) {
|
||||
// Something went wrong
|
||||
|
@ -2688,14 +2943,16 @@ export class WalletRPC {
|
|||
|
||||
async closeWallet() {
|
||||
clearInterval(this.heartbeat);
|
||||
clearInterval(this.lnsHeartbeat);
|
||||
clearInterval(this.onsHeartbeat);
|
||||
this.wallet_state = {
|
||||
open: false,
|
||||
name: "",
|
||||
password_hash: null,
|
||||
balance: null,
|
||||
unlocked_balance: null,
|
||||
lnsRecords: []
|
||||
accrued_balance: null,
|
||||
accrued_balance_next_payout: null,
|
||||
onsRecords: []
|
||||
};
|
||||
|
||||
this.purchasedNames = {};
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<q-dialog v-model="isVisible" maximized class="address-book-details">
|
||||
<q-layout v-if="mode == 'edit' || mode == 'new'">
|
||||
<q-header>
|
||||
<q-toolbar color="dark" inverted>
|
||||
<q-toolbar inverted>
|
||||
<q-btn flat round dense icon="reply" @click="close()" />
|
||||
<q-toolbar-title v-if="mode == 'new'">
|
||||
{{ $t("strings.addAddressBookEntry") }}
|
||||
|
@ -26,16 +26,15 @@
|
|||
/>
|
||||
</q-toolbar>
|
||||
</q-header>
|
||||
<q-page-container>
|
||||
<q-page-container class="detail-page">
|
||||
<div class="address-book-modal q-mx-md">
|
||||
<LokiField
|
||||
<OxenField
|
||||
:label="$t('fieldLabels.address')"
|
||||
:error="$v.newEntry.address.$error"
|
||||
>
|
||||
<q-input
|
||||
v-model.trim="newEntry.address"
|
||||
:placeholder="address_placeholder"
|
||||
:dark="theme == 'dark'"
|
||||
borderless
|
||||
dense
|
||||
@blur="$v.newEntry.address.$touch"
|
||||
|
@ -47,26 +46,20 @@
|
|||
:icon="newEntry.starred ? 'star' : 'star_border'"
|
||||
@click="updateStarred"
|
||||
/>
|
||||
</LokiField>
|
||||
<LokiField :label="$t('fieldLabels.name')">
|
||||
<q-input
|
||||
v-model.trim="newEntry.name"
|
||||
:dark="theme == 'dark'"
|
||||
borderless
|
||||
dense
|
||||
/>
|
||||
</LokiField>
|
||||
<LokiField :label="$t('fieldLabels.notes')" optional>
|
||||
</OxenField>
|
||||
<OxenField :label="$t('fieldLabels.name')">
|
||||
<q-input v-model.trim="newEntry.name" borderless dense />
|
||||
</OxenField>
|
||||
<OxenField :label="$t('fieldLabels.notes')" optional>
|
||||
<q-input
|
||||
v-model="newEntry.description"
|
||||
:placeholder="$t('placeholders.additionalNotes')"
|
||||
type="textarea"
|
||||
class="full-width text-area-loki"
|
||||
:dark="theme == 'dark'"
|
||||
class="full-width text-area-oxen"
|
||||
borderless
|
||||
dense
|
||||
/>
|
||||
</LokiField>
|
||||
</OxenField>
|
||||
|
||||
<q-btn
|
||||
v-if="mode == 'edit'"
|
||||
|
@ -81,7 +74,7 @@
|
|||
|
||||
<q-layout v-else>
|
||||
<q-header>
|
||||
<q-toolbar color="dark" inverted>
|
||||
<q-toolbar inverted>
|
||||
<q-btn flat round dense icon="reply" @click="close()" />
|
||||
<q-toolbar-title>
|
||||
{{ $t("strings.addressBookDetails") }}
|
||||
|
@ -106,6 +99,7 @@
|
|||
<div class="layout-padding">
|
||||
<template v-if="entry != null">
|
||||
<AddressHeader
|
||||
class="address-details"
|
||||
:address="entry.address"
|
||||
:title="entry.name"
|
||||
:extra="
|
||||
|
@ -140,7 +134,7 @@
|
|||
import { mapState } from "vuex";
|
||||
import AddressHeader from "components/address_header";
|
||||
import TxList from "components/tx_list";
|
||||
import LokiField from "components/loki_field";
|
||||
import OxenField from "components/oxen_field";
|
||||
import { address } from "src/validators/common";
|
||||
import { required } from "vuelidate/lib/validators";
|
||||
export default {
|
||||
|
@ -148,7 +142,7 @@ export default {
|
|||
components: {
|
||||
AddressHeader,
|
||||
TxList,
|
||||
LokiField
|
||||
OxenField
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -256,9 +250,12 @@ export default {
|
|||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.address-details {
|
||||
color: #1f1c47;
|
||||
}
|
||||
.address-book-details {
|
||||
.address-book-modal {
|
||||
> .loki-field {
|
||||
> .oxen-field {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,11 +7,20 @@
|
|||
<q-toolbar-title>
|
||||
{{ $t("titles.addressDetails") }}
|
||||
</q-toolbar-title>
|
||||
<q-btn flat :label="$t('buttons.showQRCode')" @click="isQRCodeVisible = true" />
|
||||
<q-btn class="q-ml-sm" color="primary" :label="$t('buttons.copyAddress')" @click="copyAddress()" />
|
||||
<q-btn
|
||||
flat
|
||||
:label="$t('buttons.showQRCode')"
|
||||
@click="isQRCodeVisible = true"
|
||||
/>
|
||||
<q-btn
|
||||
class="q-ml-sm"
|
||||
color="primary"
|
||||
:label="$t('buttons.copyAddress')"
|
||||
@click="copyAddress()"
|
||||
/>
|
||||
</q-toolbar>
|
||||
</q-header>
|
||||
<q-page-container>
|
||||
<q-page-container class="detail-page">
|
||||
<div class="layout-padding">
|
||||
<template v-if="address != null">
|
||||
<AddressHeader
|
||||
|
@ -26,10 +35,10 @@
|
|||
<div class="infoBox">
|
||||
<div class="infoBoxContent">
|
||||
<div class="text">
|
||||
<span>{{ $t("strings.lokiBalance") }}</span>
|
||||
<span>{{ $t("strings.oxenBalance") }}</span>
|
||||
</div>
|
||||
<div class="value">
|
||||
<span><FormatLoki :amount="address.balance"/></span>
|
||||
<span><FormatOxen :amount="address.balance"/></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -37,10 +46,12 @@
|
|||
<div class="infoBox">
|
||||
<div class="infoBoxContent">
|
||||
<div class="text">
|
||||
<span>{{ $t("strings.lokiUnlockedBalance") }}</span>
|
||||
<span>{{ $t("strings.oxenUnlockedBalance") }}</span>
|
||||
</div>
|
||||
<div class="value">
|
||||
<span><FormatLoki :amount="address.unlocked_balance"/></span>
|
||||
<span
|
||||
><FormatOxen :amount="address.unlocked_balance"
|
||||
/></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -62,7 +73,7 @@
|
|||
<div class="infoBox">
|
||||
<div class="infoBoxContent">
|
||||
<div class="text">
|
||||
<span>{{ $t("strings.lokiBalance") }}</span>
|
||||
<span>{{ $t("strings.oxenBalance") }}</span>
|
||||
</div>
|
||||
<div class="value"><span>N/A</span></div>
|
||||
</div>
|
||||
|
@ -71,7 +82,7 @@
|
|||
<div class="infoBox">
|
||||
<div class="infoBoxContent">
|
||||
<div class="text">
|
||||
<span>{{ $t("strings.lokiUnlockedBalance") }}</span>
|
||||
<span>{{ $t("strings.oxenUnlockedBalance") }}</span>
|
||||
</div>
|
||||
<div class="value"><span>N/A</span></div>
|
||||
</div>
|
||||
|
@ -91,7 +102,9 @@
|
|||
<div class="q-mt-sm">
|
||||
<div class="non-selectable recent-transactions-wrapper">
|
||||
<q-icon name="history" size="24px" />
|
||||
<span class="vertical-middle q-ml-xs">{{ $t("strings.recentIncomingTransactionsToAddress") }}</span>
|
||||
<span class="vertical-middle q-ml-xs">{{
|
||||
$t("strings.recentIncomingTransactionsToAddress")
|
||||
}}</span>
|
||||
</div>
|
||||
|
||||
<div style="margin: 12px -16px;">
|
||||
|
@ -108,12 +121,21 @@
|
|||
</q-page-container>
|
||||
</q-layout>
|
||||
<template v-if="address != null">
|
||||
<q-dialog v-model="isQRCodeVisible" minimized :content-class="'qr-code-modal'">
|
||||
<q-dialog
|
||||
v-model="isQRCodeVisible"
|
||||
minimized
|
||||
:content-class="'qr-code-modal'"
|
||||
>
|
||||
<q-card class="qr-code-card">
|
||||
<div class="text-center q-mb-sm q-pa-md" style="background: white;">
|
||||
<QrcodeVue ref="qr" :value="address.address" size="240"> </QrcodeVue>
|
||||
<QrcodeVue ref="qr" :value="address.address" size="240">
|
||||
</QrcodeVue>
|
||||
<q-menu content-menu>
|
||||
<q-list link separator style="min-width: 150px; max-height: 300px;">
|
||||
<q-list
|
||||
link
|
||||
separator
|
||||
style="min-width: 150px; max-height: 300px;"
|
||||
>
|
||||
<q-item v-close-popup @click.native="copyQR()">
|
||||
<q-item-label :label="$t('menuItems.copyQR')" />
|
||||
</q-item>
|
||||
|
@ -124,7 +146,11 @@
|
|||
</q-menu>
|
||||
</div>
|
||||
<q-card-actions>
|
||||
<q-btn color="primary" :label="$t('buttons.close')" @click="isQRCodeVisible = false" />
|
||||
<q-btn
|
||||
color="primary"
|
||||
:label="$t('buttons.close')"
|
||||
@click="isQRCodeVisible = false"
|
||||
/>
|
||||
</q-card-actions>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
|
@ -136,7 +162,7 @@
|
|||
import { mapState } from "vuex";
|
||||
const { clipboard, nativeImage } = require("electron");
|
||||
import AddressHeader from "components/address_header";
|
||||
import FormatLoki from "components/format_loki";
|
||||
import FormatOxen from "components/format_oxen";
|
||||
import QrcodeVue from "qrcode.vue";
|
||||
import TxList from "components/tx_list";
|
||||
export default {
|
||||
|
@ -144,7 +170,7 @@ export default {
|
|||
components: {
|
||||
AddressHeader,
|
||||
TxList,
|
||||
FormatLoki,
|
||||
FormatOxen,
|
||||
QrcodeVue
|
||||
},
|
||||
data() {
|
||||
|
@ -169,7 +195,9 @@ export default {
|
|||
")";
|
||||
}
|
||||
|
||||
const extra = this.address.used ? this.$t("strings.userUsedAddress") : this.$t("strings.userNotUsedAddress");
|
||||
const extra = this.address.used
|
||||
? this.$t("strings.userUsedAddress")
|
||||
: this.$t("strings.userNotUsedAddress");
|
||||
|
||||
return {
|
||||
title,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="address-header-div">
|
||||
<q-item-section class="self-start">
|
||||
<q-item-label class="title non-selectable">{{ title }}</q-item-label>
|
||||
<q-item-label class="row">
|
||||
|
@ -87,17 +87,18 @@ export default {
|
|||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.title {
|
||||
font-size: 18px;
|
||||
margin-bottom: 4px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.extra {
|
||||
margin-top: 8px;
|
||||
color: white;
|
||||
.address-header-div {
|
||||
.title {
|
||||
font-size: 20px;
|
||||
color: #1f1c47;
|
||||
}
|
||||
|
||||
.extra {
|
||||
color: #1f1c47;
|
||||
}
|
||||
}
|
||||
|
||||
// is this even used?
|
||||
.address-header {
|
||||
padding: 0;
|
||||
img {
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
<template>
|
||||
<div class="check-transaction">
|
||||
<div class="q-pa-md">
|
||||
<div class="q-mb-lg description">{{ $t("strings.checkTransaction.description") }}</div>
|
||||
<div class="q-mb-lg tab-desc">
|
||||
{{ $t("strings.checkTransaction.description") }}
|
||||
</div>
|
||||
<div>
|
||||
<LokiField :label="$t('fieldLabels.transactionId')" :error="$v.txid.$error">
|
||||
<OxenField
|
||||
:label="$t('fieldLabels.transactionId')"
|
||||
:error="$v.txid.$error"
|
||||
>
|
||||
<q-input
|
||||
v-model.trim="txid"
|
||||
:dark="theme == 'dark'"
|
||||
|
@ -12,8 +17,13 @@
|
|||
dense
|
||||
@blur="$v.txid.$touch"
|
||||
/>
|
||||
</LokiField>
|
||||
<LokiField class="q-mt-md" :label="$t('fieldLabels.address')" :error="$v.address.$error" optional>
|
||||
</OxenField>
|
||||
<OxenField
|
||||
class="q-mt-md"
|
||||
:label="$t('fieldLabels.address')"
|
||||
:error="$v.address.$error"
|
||||
optional
|
||||
>
|
||||
<q-input
|
||||
v-model.trim="address"
|
||||
:dark="theme == 'dark'"
|
||||
|
@ -22,8 +32,8 @@
|
|||
dense
|
||||
@blur="$v.address.$touch"
|
||||
/>
|
||||
</LokiField>
|
||||
<LokiField class="q-mt-md" :label="$t('fieldLabels.message')" optional>
|
||||
</OxenField>
|
||||
<OxenField class="q-mt-md" :label="$t('fieldLabels.message')" optional>
|
||||
<q-input
|
||||
v-model.trim="message"
|
||||
:dark="theme == 'dark'"
|
||||
|
@ -31,8 +41,12 @@
|
|||
borderless
|
||||
dense
|
||||
/>
|
||||
</LokiField>
|
||||
<LokiField class="q-mt-md" :label="$t('fieldLabels.signature')" :error="$v.signature.$error">
|
||||
</OxenField>
|
||||
<OxenField
|
||||
class="q-mt-md"
|
||||
:label="$t('fieldLabels.signature')"
|
||||
:error="$v.signature.$error"
|
||||
>
|
||||
<q-input
|
||||
v-model.trim="signature"
|
||||
:dark="theme == 'dark'"
|
||||
|
@ -40,10 +54,15 @@
|
|||
borderless
|
||||
dense
|
||||
/>
|
||||
</LokiField>
|
||||
</OxenField>
|
||||
<div class="submit-button">
|
||||
<q-btn color="primary" :label="$t('buttons.check')" @click="check" />
|
||||
<q-btn v-if="canClear" color="secondary" :label="$t('buttons.clear')" @click="clear" />
|
||||
<q-btn
|
||||
v-if="canClear"
|
||||
color="secondsary="
|
||||
:label="$t('buttons.clear')"
|
||||
@click="clear"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="status.state.txid">
|
||||
|
@ -52,21 +71,31 @@
|
|||
<div>{{ status.state.txid }}</div>
|
||||
</div>
|
||||
<div class="q-mb-sm">
|
||||
<div class="title">{{ $t("strings.checkTransaction.infoTitles.validTransaction") }}</div>
|
||||
<div :class="status.state.good ? 'good' : 'bad'">{{ validTransaction }}</div>
|
||||
<div class="title">
|
||||
{{ $t("strings.checkTransaction.infoTitles.validTransaction") }}
|
||||
</div>
|
||||
<div :class="status.state.good ? 'good' : 'bad'">
|
||||
{{ validTransaction }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="status.state.received != null" class="q-mb-sm">
|
||||
<div class="title">{{ $t("strings.checkTransaction.infoTitles.received") }}</div>
|
||||
<div class="title">
|
||||
{{ $t("strings.checkTransaction.infoTitles.received") }}
|
||||
</div>
|
||||
<div>
|
||||
<FormatLoki :amount="status.state.received" raw-value />
|
||||
<FormatOxen :amount="status.state.received" raw-value />
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="status.state.in_pool != null" class="q-mb-sm">
|
||||
<div class="title">{{ $t("strings.checkTransaction.infoTitles.inPool") }}</div>
|
||||
<div class="title">
|
||||
{{ $t("strings.checkTransaction.infoTitles.inPool") }}
|
||||
</div>
|
||||
<div>{{ status.state.in_pool }}</div>
|
||||
</div>
|
||||
<div v-if="status.state.confirmations != null" class="q-mb-sm">
|
||||
<div class="title">{{ $t("strings.checkTransaction.infoTitles.confirmations") }}</div>
|
||||
<div class="title">
|
||||
{{ $t("strings.checkTransaction.infoTitles.confirmations") }}
|
||||
</div>
|
||||
<div>{{ status.state.confirmations }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -79,14 +108,14 @@ import { mapState } from "vuex";
|
|||
import { required } from "vuelidate/lib/validators";
|
||||
import { address } from "src/validators/common";
|
||||
import { i18n } from "boot/i18n";
|
||||
import LokiField from "components/loki_field";
|
||||
import FormatLoki from "components/format_loki";
|
||||
import OxenField from "components/oxen_field";
|
||||
import FormatOxen from "components/format_oxen";
|
||||
|
||||
export default {
|
||||
name: "CheckTransaction",
|
||||
components: {
|
||||
LokiField,
|
||||
FormatLoki
|
||||
OxenField,
|
||||
FormatOxen
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -100,7 +129,12 @@ export default {
|
|||
theme: state => state.gateway.app.config.appearance.theme,
|
||||
status: state => state.gateway.check_transaction_status,
|
||||
canClear() {
|
||||
return this.txid !== "" || this.address !== "" || this.message !== "" || this.signature != "";
|
||||
return (
|
||||
this.txid !== "" ||
|
||||
this.address !== "" ||
|
||||
this.message !== "" ||
|
||||
this.signature != ""
|
||||
);
|
||||
},
|
||||
validTransaction() {
|
||||
let key = this.status.state.good ? "yes" : "no";
|
|
@ -1,11 +1,14 @@
|
|||
<template>
|
||||
<div class="prove-transaction">
|
||||
<div class="q-pa-md">
|
||||
<div class="q-mb-lg description">
|
||||
<div class="q-mb-lg tab-desc">
|
||||
{{ $t("strings.proveTransactionDescription") }}
|
||||
</div>
|
||||
<div>
|
||||
<LokiField :label="$t('fieldLabels.transactionId')" :error="$v.txid.$error">
|
||||
<OxenField
|
||||
:label="$t('fieldLabels.transactionId')"
|
||||
:error="$v.txid.$error"
|
||||
>
|
||||
<q-input
|
||||
v-model.trim="txid"
|
||||
:dark="theme == 'dark'"
|
||||
|
@ -14,8 +17,13 @@
|
|||
dense
|
||||
@blur="$v.txid.$touch"
|
||||
/>
|
||||
</LokiField>
|
||||
<LokiField class="q-mt-md" :label="$t('fieldLabels.address')" :error="$v.address.$error" optional>
|
||||
</OxenField>
|
||||
<OxenField
|
||||
class="q-mt-md"
|
||||
:label="$t('fieldLabels.address')"
|
||||
:error="$v.address.$error"
|
||||
optional
|
||||
>
|
||||
<q-input
|
||||
v-model.trim="address"
|
||||
:dark="theme == 'dark'"
|
||||
|
@ -24,8 +32,8 @@
|
|||
dense
|
||||
@blur="$v.address.$touch"
|
||||
/>
|
||||
</LokiField>
|
||||
<LokiField class="q-mt-md" :label="$t('fieldLabels.message')" optional>
|
||||
</OxenField>
|
||||
<OxenField class="q-mt-md" :label="$t('fieldLabels.message')" optional>
|
||||
<q-input
|
||||
v-model.trim="message"
|
||||
:dark="theme == 'dark'"
|
||||
|
@ -33,11 +41,25 @@
|
|||
borderless
|
||||
dense
|
||||
/>
|
||||
</LokiField>
|
||||
</OxenField>
|
||||
<div class="buttons submit-button">
|
||||
<q-btn color="primary" :label="$t('buttons.generate')" @click="generate" />
|
||||
<q-btn v-if="canClear" color="secondary" :label="$t('buttons.clear')" @click="clear" />
|
||||
<q-btn v-if="status.state.signature" color="secondary" :label="$t('buttons.copySignature')" @click="copy" />
|
||||
<q-btn
|
||||
color="primary"
|
||||
:label="$t('buttons.generate')"
|
||||
@click="generate"
|
||||
/>
|
||||
<q-btn
|
||||
v-if="canClear"
|
||||
color="accent"
|
||||
:label="$t('buttons.clear')"
|
||||
@click="clear"
|
||||
/>
|
||||
<q-btn
|
||||
v-if="status.state.signature"
|
||||
color="secondary"
|
||||
:label="$t('buttons.copySignature')"
|
||||
@click="copy"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="status.state.signature" class="signature-wrapper">
|
||||
|
@ -57,13 +79,13 @@
|
|||
import { mapState } from "vuex";
|
||||
import { required } from "vuelidate/lib/validators";
|
||||
import { address } from "src/validators/common";
|
||||
import LokiField from "components/loki_field";
|
||||
import OxenField from "components/oxen_field";
|
||||
import { clipboard } from "electron";
|
||||
|
||||
export default {
|
||||
name: "ProveTransaction",
|
||||
components: {
|
||||
LokiField
|
||||
OxenField
|
||||
},
|
||||
data() {
|
||||
return {
|
|
@ -0,0 +1,246 @@
|
|||
<template>
|
||||
<div class="sign-and-verify">
|
||||
<div class="q-pa-md">
|
||||
<div class="q-mb-lg tab-desc">
|
||||
{{ $t("strings.signAndVerifyDescription") }}
|
||||
</div>
|
||||
<div v-if="is_view_only">
|
||||
{{ $t("strings.cannotSign") }}
|
||||
</div>
|
||||
<div v-else>
|
||||
<div class="text-h6 header">{{ $t("titles.advanced.sign") }}</div>
|
||||
<div class="row justify-between items-end">
|
||||
<OxenField :label="$t('fieldLabels.data')">
|
||||
<q-input
|
||||
v-model.trim="toSign"
|
||||
:dark="theme == 'dark'"
|
||||
borderless
|
||||
dense
|
||||
:placeholder="$t('placeholders.dataToSign')"
|
||||
/>
|
||||
</OxenField>
|
||||
<div class="btn-wrapper q-ml-md q-py-sm">
|
||||
<q-btn
|
||||
color="primary"
|
||||
:label="$t('buttons.sign')"
|
||||
:loading="sign_status.sending"
|
||||
:disable="!toSign"
|
||||
@click="sign()"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="verify-heading text-h6 header">
|
||||
{{ $t("titles.advanced.verify") }}
|
||||
</div>
|
||||
<div class="justify-between items-end">
|
||||
<OxenField class="q-mt-md" :label="$t('fieldLabels.signature')">
|
||||
<q-input
|
||||
v-model.trim="signatureToVerify"
|
||||
:dark="theme == 'dark'"
|
||||
borderless
|
||||
dense
|
||||
:placeholder="$t('placeholders.signature')"
|
||||
/>
|
||||
</OxenField>
|
||||
<OxenField class="q-mt-md" :label="$t('fieldLabels.data')">
|
||||
<q-input
|
||||
v-model.trim="unsignedData"
|
||||
:dark="theme == 'dark'"
|
||||
borderless
|
||||
dense
|
||||
:placeholder="$t('placeholders.unsignedData')"
|
||||
/>
|
||||
</OxenField>
|
||||
<OxenField class="q-mt-md" :label="$t('fieldLabels.address')">
|
||||
<q-input
|
||||
v-model.trim="address"
|
||||
:dark="theme == 'dark'"
|
||||
borderless
|
||||
dense
|
||||
:placeholder="$t('placeholders.addressOfSigner')"
|
||||
/>
|
||||
</OxenField>
|
||||
<div class="submit-button">
|
||||
<q-btn
|
||||
color="primary"
|
||||
:label="$t('buttons.verify')"
|
||||
:disable="!signatureToVerify || !unsignedData || !address"
|
||||
@click="verify()"
|
||||
/>
|
||||
<q-btn
|
||||
v-if="canClear"
|
||||
:label="$t('buttons.clear')"
|
||||
color="accent"
|
||||
@click="clear"
|
||||
/>
|
||||
</div>
|
||||
<SignatureDialog
|
||||
:on-copy-signature="copySignature"
|
||||
:on-copy-unsigned-data="copyUnsignedData"
|
||||
:on-copy-address="copyAddress"
|
||||
:on-close="closeDialog"
|
||||
:signature="signature"
|
||||
:unsigned-data="toSign"
|
||||
:address="primary_address"
|
||||
:show="!!signature"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const { clipboard } = require("electron");
|
||||
import OxenField from "components/oxen_field";
|
||||
import SignatureDialog from "./signature_dialog";
|
||||
import { mapState } from "vuex";
|
||||
export default {
|
||||
name: "SignAndVerify",
|
||||
components: {
|
||||
OxenField,
|
||||
SignatureDialog
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
toSign: "",
|
||||
// entered by the user to verify
|
||||
signatureToVerify: "",
|
||||
unsignedData: "",
|
||||
address: ""
|
||||
};
|
||||
},
|
||||
computed: mapState({
|
||||
theme: state => state.gateway.app.config.appearance.theme,
|
||||
sign_status: state => state.gateway.sign_status,
|
||||
verify_status: state => state.gateway.verify_status,
|
||||
signature: state => state.gateway.sign_status.signature,
|
||||
primary_address: state => state.gateway.wallet.info.address,
|
||||
is_view_only: state => state.gateway.wallet.info.view_only,
|
||||
canClear() {
|
||||
const canClear =
|
||||
this.signatureToVerify !== "" ||
|
||||
this.address !== "" ||
|
||||
this.unsignedData !== "";
|
||||
return canClear;
|
||||
}
|
||||
}),
|
||||
watch: {
|
||||
sign_status: {
|
||||
handler(val, old) {
|
||||
if (val.code == old.code) return;
|
||||
const { code, message } = val;
|
||||
switch (code) {
|
||||
case -1:
|
||||
this.$q.notify({
|
||||
type: "negative",
|
||||
timeout: 3000,
|
||||
message
|
||||
});
|
||||
break;
|
||||
}
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
verify_status: {
|
||||
handler(val, old) {
|
||||
if (val.code == old.code) return;
|
||||
const { code, message, i18n } = val;
|
||||
switch (code) {
|
||||
case -1:
|
||||
this.$q.notify({
|
||||
type: "negative",
|
||||
timeout: 3000,
|
||||
message: i18n ? this.$t(i18n) : message
|
||||
});
|
||||
break;
|
||||
case 1:
|
||||
this.$q.notify({
|
||||
type: "positive",
|
||||
timeout: 3000,
|
||||
message: i18n ? this.$t(i18n) : message
|
||||
});
|
||||
break;
|
||||
}
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
sign() {
|
||||
this.$gateway.send("wallet", "sign", { data: this.toSign });
|
||||
},
|
||||
verify() {
|
||||
this.$gateway.send("wallet", "verify", {
|
||||
address: this.address,
|
||||
data: this.unsignedData,
|
||||
signature: this.signatureToVerify
|
||||
});
|
||||
},
|
||||
copySignature() {
|
||||
clipboard.writeText(this.signature);
|
||||
this.$q.notify({
|
||||
type: "positive",
|
||||
timeout: 2000,
|
||||
message: this.$t("notification.positive.signatureCopied")
|
||||
});
|
||||
},
|
||||
// copy from the dialog
|
||||
copyUnsignedData() {
|
||||
clipboard.writeText(this.toSign);
|
||||
this.$q.notify({
|
||||
type: "positive",
|
||||
timeout: 2000,
|
||||
message: this.$t("notification.positive.copied", { item: "Data" })
|
||||
});
|
||||
},
|
||||
copyAddress() {
|
||||
clipboard.writeText(this.primary_address);
|
||||
this.$q.notify({
|
||||
type: "positive",
|
||||
timeout: 2000,
|
||||
message: this.$t("notification.positive.addressCopied")
|
||||
});
|
||||
},
|
||||
closeDialog() {
|
||||
this.$store.commit("gateway/set_sign_status", {
|
||||
signature: ""
|
||||
});
|
||||
},
|
||||
clear() {
|
||||
this.signatureToVerify = "";
|
||||
this.unsignedData = "";
|
||||
this.address = "";
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.description {
|
||||
white-space: pre-line;
|
||||
}
|
||||
.sign-and-verify {
|
||||
.height {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
.q-item {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.oxen-field {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.verify-heading {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.submit-button {
|
||||
.q-btn:not(:first-child) {
|
||||
margin-left: 8px;
|
||||
}
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,150 @@
|
|||
<template>
|
||||
<q-dialog v-model="show" persistent>
|
||||
<q-card class="signature-dialog">
|
||||
<q-card-section>
|
||||
<div class="text-h6">{{ $t("dialog.signature.title") }}</div>
|
||||
<div>
|
||||
{{ $t("dialog.signature.message") }}
|
||||
</div>
|
||||
</q-card-section>
|
||||
<q-card-section class="info">
|
||||
<q-item class="signature row">
|
||||
<div class="col">
|
||||
<q-item-label class="labels">{{
|
||||
$t("fieldLabels.signature")
|
||||
}}</q-item-label>
|
||||
{{ signature }}
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<q-btn
|
||||
color="primary"
|
||||
icon="file_copy"
|
||||
size="sm"
|
||||
padding="xs"
|
||||
style="width: 100%; margin-top: 16px"
|
||||
@click="onCopySignature"
|
||||
>
|
||||
<q-tooltip
|
||||
anchor="center left"
|
||||
self="center right"
|
||||
:offset="[5, 10]"
|
||||
>
|
||||
{{ $t("buttons.copySignature") }}
|
||||
</q-tooltip>
|
||||
</q-btn>
|
||||
</div>
|
||||
</q-item>
|
||||
<q-item class="row unsigned-data">
|
||||
<div class="col">
|
||||
<q-item-label class="labels">{{
|
||||
$t("fieldLabels.data")
|
||||
}}</q-item-label>
|
||||
{{ unsignedData }}
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<q-btn
|
||||
color="primary"
|
||||
icon="file_copy"
|
||||
size="sm"
|
||||
padding="xs"
|
||||
style="width: 100%; margin-top: 16px"
|
||||
@click="onCopyUnsignedData"
|
||||
>
|
||||
<q-tooltip
|
||||
anchor="center left"
|
||||
self="center right"
|
||||
:offset="[5, 10]"
|
||||
>
|
||||
{{ $t("buttons.copyData") }}
|
||||
</q-tooltip>
|
||||
</q-btn>
|
||||
</div>
|
||||
</q-item>
|
||||
<q-item class="row address">
|
||||
<div class="col">
|
||||
<q-item-label class="labels">{{
|
||||
$t("fieldLabels.address")
|
||||
}}</q-item-label>
|
||||
{{ address }}
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<q-btn
|
||||
color="primary"
|
||||
class="vertical-middle"
|
||||
icon="file_copy"
|
||||
size="sm"
|
||||
style="width: 100%; margin-top: 16px"
|
||||
padding="xs"
|
||||
@click="onCopyAddress"
|
||||
>
|
||||
<q-tooltip
|
||||
anchor="center left"
|
||||
self="center right"
|
||||
:offset="[5, 10]"
|
||||
>
|
||||
{{ $t("buttons.copyAddress") }}
|
||||
</q-tooltip>
|
||||
</q-btn>
|
||||
</div>
|
||||
</q-item>
|
||||
</q-card-section>
|
||||
<q-card-actions align="right">
|
||||
<q-btn flat :label="$t('buttons.close')" @click="onClose" />
|
||||
</q-card-actions>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "SignatureDialog",
|
||||
props: {
|
||||
onCopySignature: {
|
||||
type: Function,
|
||||
required: true
|
||||
},
|
||||
onCopyAddress: {
|
||||
type: Function,
|
||||
required: true
|
||||
},
|
||||
onCopyUnsignedData: {
|
||||
type: Function,
|
||||
required: true
|
||||
},
|
||||
onClose: {
|
||||
type: Function,
|
||||
required: true
|
||||
},
|
||||
signature: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
show: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: true
|
||||
},
|
||||
address: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
unsignedData: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.info {
|
||||
flex: 1;
|
||||
word-break: break-all;
|
||||
word-wrap: break-word;
|
||||
|
||||
.labels {
|
||||
font-weight: bold;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<q-dialog v-model="show" persistent>
|
||||
<q-card class="confirm-tx-card" dark>
|
||||
<q-card class="confirm-tx-card">
|
||||
<q-card-section>
|
||||
<div class="text-h6">{{ $t("dialog.confirmTransaction.title") }}</div>
|
||||
</q-card-section>
|
||||
|
@ -15,10 +15,10 @@
|
|||
</div>
|
||||
<br />
|
||||
<span class="label">{{ $t("strings.transactions.amount") }}: </span>
|
||||
{{ amount }} Loki
|
||||
{{ amount }} OXEN
|
||||
<br />
|
||||
<span class="label">{{ $t("strings.transactions.fee") }}: </span>
|
||||
{{ fee }} Loki
|
||||
{{ fee }} OXEN
|
||||
<br />
|
||||
<span class="label"
|
||||
>{{ $t("dialog.confirmTransaction.priority") }}:
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
<template>
|
||||
<span> {{ value }} </span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "FormatNextPayout",
|
||||
props: {
|
||||
payoutBlock: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
currentBlock: {
|
||||
type: Number,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
value() {
|
||||
console.log(this.payoutBlock);
|
||||
console.log(this.currentBlock);
|
||||
if (this.payoutBlock == 0) return "";
|
||||
|
||||
let blocks = this.payoutBlock - this.currentBlock;
|
||||
console.log(this.currentBlock);
|
||||
|
||||
if (blocks > 720) return (blocks / 720).toFixed(1) + " days";
|
||||
else if (blocks > 30) return (blocks / 30).toFixed(1) + " hours";
|
||||
else return blocks * 2 + " minutes";
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
|
@ -1,10 +1,10 @@
|
|||
<template>
|
||||
<span> {{ value }} LOKI </span>
|
||||
<span> {{ value }} OXEN </span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "FormatLoki",
|
||||
name: "FormatOxen",
|
||||
props: {
|
||||
amount: {
|
||||
type: Number,
|
|
@ -8,7 +8,7 @@
|
|||
v-for="option in options"
|
||||
:key="option.value"
|
||||
class="row justify-center items-center"
|
||||
:color="lang === option.value ? 'primary' : 'secondary'"
|
||||
:color="lang === option.value ? 'primary' : 'accent'"
|
||||
size="md"
|
||||
@click="setLanguage(option.value)"
|
||||
>
|
||||
|
|
|
@ -1,66 +0,0 @@
|
|||
<template>
|
||||
<div class="lns-purchase">
|
||||
<div class="q-mb-lg q-px-md q-pt-md">
|
||||
<div class="description">
|
||||
{{ $t("strings.lnsPurchaseDescription") }}
|
||||
</div>
|
||||
<div class="prices">
|
||||
{{ $t("strings.lns.prices") }}
|
||||
<table>
|
||||
<tr>
|
||||
<td>{{ $t("strings.lns.sessionID") }}:</td>
|
||||
<td>15 LOKI</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t("strings.lns.lokinetName1Year") }}:</td>
|
||||
<td>15 LOKI</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t("strings.lns.lokinetNameXYears", { years: 2 }) }}:</td>
|
||||
<td>30 LOKI</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t("strings.lns.lokinetNameXYears", { years: 5 }) }}:</td>
|
||||
<td>60 LOKI</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t("strings.lns.lokinetNameXYears", { years: 10 }) }}:</td>
|
||||
<td>90 LOKI</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<LNSInput ref="input" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import LNSInput from "./lns_input";
|
||||
export default {
|
||||
name: "LNSPurchase",
|
||||
components: {
|
||||
LNSInput
|
||||
},
|
||||
methods: {
|
||||
startUpdating(record) {
|
||||
this.$refs.input.startUpdating(record);
|
||||
},
|
||||
startRenewing(record) {
|
||||
this.$refs.input.startRenewing(record);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.lns-purchase {
|
||||
.description {
|
||||
white-space: pre-line;
|
||||
color: #cecece;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.prices {
|
||||
color: #cecece;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -2,7 +2,11 @@
|
|||
<q-menu context-menu>
|
||||
<q-list separator class="context-menu-list">
|
||||
<div v-for="(item, index) in menuItems" :key="index">
|
||||
<ContextMenuItem :action="item.action" :i18n="item.i18n" @clicked="clickedMenu(item, $event)" />
|
||||
<ContextMenuItem
|
||||
:action="item.action"
|
||||
:i18n="item.i18n"
|
||||
@clicked="clickedMenu(item, $event)"
|
||||
/>
|
||||
</div>
|
||||
</q-list>
|
||||
</q-menu>
|
||||
|
@ -30,10 +34,4 @@ export default {
|
|||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.context-menu-list {
|
||||
min-width: 150px;
|
||||
max-height: 300px;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
<style></style>
|
||||
|
|
|
@ -3,8 +3,15 @@
|
|||
<q-btn class="menu" icon="menu" size="md" flat>
|
||||
<q-menu>
|
||||
<q-list separator class="menu-list">
|
||||
<q-item v-if="!disableSwitchWallet" v-close-popup clickable @click.native="switchWallet">
|
||||
<q-item-label header>{{ $t("menuItems.switchWallet") }}</q-item-label>
|
||||
<q-item
|
||||
v-if="!disableSwitchWallet"
|
||||
v-close-popup
|
||||
clickable
|
||||
@click.native="switchWallet"
|
||||
>
|
||||
<q-item-label header>{{
|
||||
$t("menuItems.switchWallet")
|
||||
}}</q-item-label>
|
||||
</q-item>
|
||||
<q-item v-close-popup clickable @click.native="openSettings">
|
||||
<q-item-label header>{{ $t("menuItems.settings") }}</q-item-label>
|
||||
|
@ -22,26 +29,47 @@
|
|||
<!-- TODO: Move this to it's own component -->
|
||||
<q-dialog ref="aboutModal" minimized>
|
||||
<div class="about-modal">
|
||||
<img class="q-mb-md" src="loki.svg" height="42" />
|
||||
<img class="q-mb-md" src="oxen.svg" height="42" />
|
||||
|
||||
<p class="q-my-sm">Wallet Version: v{{ version }}</p>
|
||||
<p class="q-my-sm">Deaemon Version: v{{ daemonVersion }}</p>
|
||||
<p class="q-my-sm">Copyright (c) 2018-2020, Loki Project</p>
|
||||
<p class="q-my-sm">Daemon Version: v{{ daemonVersion }}</p>
|
||||
<p class="q-my-sm">Copyright (c) 2018-2021, Oxen</p>
|
||||
<p class="q-my-sm">Copyright (c) 2018, Ryo Currency Project</p>
|
||||
<p class="q-my-sm">All rights reserved.</p>
|
||||
|
||||
<div class="q-mt-md q-mb-lg external-links">
|
||||
<p>
|
||||
<a href="#" @click="openExternal('https://loki.network/')">https://loki.network/</a>
|
||||
<a href="#" @click="openExternal('https://oxen.io/')"
|
||||
>https://oxen.io/</a
|
||||
>
|
||||
</p>
|
||||
<p>
|
||||
<a href="#" @click="openExternal('https://t.me/joinchat/DeNvR0JJ4JPn6TVSQjCsZQ')">Telegram</a>
|
||||
<a href="#" @click="openExternal('https://t.me/Oxen_Community')"
|
||||
>Telegram</a
|
||||
>
|
||||
-
|
||||
<a href="#" @click="openExternal('https://discordapp.com/invite/67GXfD6')">Discord</a>
|
||||
<a
|
||||
href="#"
|
||||
@click="openExternal('https://discordapp.com/invite/67GXfD6')"
|
||||
>Discord</a
|
||||
>
|
||||
-
|
||||
<a href="#" @click="openExternal('https://www.reddit.com/r/LokiProject/')">Reddit</a>
|
||||
-
|
||||
<a href="#" @click="openExternal('https://github.com/loki-project/loki-electron-gui-wallet')">Github</a>
|
||||
<!-- readded once oxen subreddit is known -->
|
||||
<!-- <a
|
||||
href="#"
|
||||
@click="openExternal('https://www.reddit.com/r/LokiProject/')"
|
||||
>Reddit</a
|
||||
>
|
||||
- -->
|
||||
<a
|
||||
href="#"
|
||||
@click="
|
||||
openExternal(
|
||||
'https://github.com/loki-project/loki-electron-gui-wallet'
|
||||
)
|
||||
"
|
||||
>Github</a
|
||||
>
|
||||
</p>
|
||||
</div>
|
||||
<q-btn color="primary" label="Close" @click="showAbout(false)" />
|
||||
|
@ -96,13 +124,19 @@ export default {
|
|||
switchWallet() {
|
||||
// If the rpc is syncing then we want to tell the user to restart
|
||||
if (this.isRPCSyncing) {
|
||||
this.$gateway.confirmClose(this.$t("dialog.switchWallet.restartMessage"), true);
|
||||
this.$gateway.confirmClose(
|
||||
this.$t("dialog.switchWallet.restartMessage"),
|
||||
true
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Remove this in hardfork 16
|
||||
// This is a temporary work around for the issue where wallet rpc hangs after closing a wallet due to long polling still being active
|
||||
this.$gateway.confirmClose(this.$t("dialog.switchWallet.restartWalletMessage"), true);
|
||||
this.$gateway.confirmClose(
|
||||
this.$t("dialog.switchWallet.restartWalletMessage"),
|
||||
true
|
||||
);
|
||||
|
||||
// Allow switching normally because rpc won't be blocked
|
||||
// NB: If this is added back, must use the quasar v1 APIs
|
||||
|
@ -142,8 +176,8 @@ export default {
|
|||
<style lang="scss">
|
||||
.about-modal {
|
||||
padding: 25px;
|
||||
background-color: $dark;
|
||||
color: white;
|
||||
background-color: white;
|
||||
color: #1f1c47;
|
||||
|
||||
.external-links {
|
||||
a {
|
||||
|
|
|
@ -1,22 +1,72 @@
|
|||
<template>
|
||||
<div class="wallet-settings">
|
||||
<q-btn icon-right="more_vert" :label="$t('buttons.settings')" size="md" flat>
|
||||
<q-btn
|
||||
icon-right="more_vert"
|
||||
:label="$t('buttons.settings')"
|
||||
size="md"
|
||||
flat
|
||||
>
|
||||
<q-menu anchor="bottom right" self="top right">
|
||||
<q-list separator class="menu-list">
|
||||
<q-item v-close-popup clickable :disabled="!is_ready" @click.native="getPrivateKeys()">
|
||||
<q-item-label header>{{ $t("menuItems.showPrivateKeys") }}</q-item-label>
|
||||
<q-item
|
||||
v-close-popup
|
||||
clickable
|
||||
:disabled="!is_ready"
|
||||
@click.native="getPrivateKeys()"
|
||||
>
|
||||
<q-item-label header>{{
|
||||
$t("menuItems.showPrivateKeys")
|
||||
}}</q-item-label>
|
||||
</q-item>
|
||||
<q-item v-close-popup clickable :disabled="!is_ready" @click.native="showModal('change_password')">
|
||||
<q-item-label header>{{ $t("menuItems.changePassword") }}</q-item-label>
|
||||
<q-item
|
||||
v-close-popup
|
||||
clickable
|
||||
:disabled="!is_ready"
|
||||
@click.native="showModal('change_password')"
|
||||
>
|
||||
<q-item-label header>{{
|
||||
$t("menuItems.changePassword")
|
||||
}}</q-item-label>
|
||||
</q-item>
|
||||
<q-item v-close-popup clickable :disabled="!is_ready" @click.native="showModal('rescan')">
|
||||
<q-item-label header>{{ $t("menuItems.rescanWallet") }}</q-item-label>
|
||||
<q-item
|
||||
v-close-popup
|
||||
clickable
|
||||
:disabled="!is_ready"
|
||||
@click.native="showModal('export_transfers')"
|
||||
>
|
||||
<q-item-label header>{{
|
||||
$t("menuItems.exportTransfers")
|
||||
}}</q-item-label>
|
||||
</q-item>
|
||||
<q-item v-close-popup clickable :disabled="!is_ready" @click.native="showModal('key_image')">
|
||||
<q-item-label header>{{ $t("menuItems.manageKeyImages") }}</q-item-label>
|
||||
<q-item
|
||||
v-close-popup
|
||||
clickable
|
||||
:disabled="!is_ready"
|
||||
@click.native="showModal('rescan')"
|
||||
>
|
||||
<q-item-label header>{{
|
||||
$t("menuItems.rescanWallet")
|
||||
}}</q-item-label>
|
||||
</q-item>
|
||||
<q-item v-close-popup clickable :disabled="!is_ready" @click.native="deleteWallet()">
|
||||
<q-item-label header>{{ $t("menuItems.deleteWallet") }}</q-item-label>
|
||||
<q-item
|
||||
v-close-popup
|
||||
clickable
|
||||
:disabled="!is_ready"
|
||||
@click.native="showModal('key_image')"
|
||||
>
|
||||
<q-item-label header>{{
|
||||
$t("menuItems.manageKeyImages")
|
||||
}}</q-item-label>
|
||||
</q-item>
|
||||
<q-item
|
||||
v-close-popup
|
||||
clickable
|
||||
:disabled="!is_ready"
|
||||
@click.native="deleteWallet()"
|
||||
>
|
||||
<q-item-label header>{{
|
||||
$t("menuItems.deleteWallet")
|
||||
}}</q-item-label>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</q-menu>
|
||||
|
@ -24,10 +74,14 @@
|
|||
|
||||
<!-- Modals -->
|
||||
<!-- PRIVATE KEY MODAL -->
|
||||
<q-dialog v-model="modals.private_keys.visible" minimized class="private-key-modal" @hide="closePrivateKeys()">
|
||||
<div class="modal">
|
||||
<q-dialog
|
||||
v-model="modals.private_keys.visible"
|
||||
minimized
|
||||
@hide="closePrivateKeys()"
|
||||
>
|
||||
<div class="modal private-key-modal">
|
||||
<div class="modal-header">{{ $t("titles.privateKeys") }}</div>
|
||||
<div class="q-ma-lg">
|
||||
<div class="q-ma-md">
|
||||
<template v-if="secret.mnemonic">
|
||||
<h6 class="q-mb-xs q-mt-lg">
|
||||
{{ $t("strings.seedWords") }}
|
||||
|
@ -45,7 +99,11 @@
|
|||
icon="file_copy"
|
||||
@click="copyPrivateKey('mnemonic', $event)"
|
||||
>
|
||||
<q-tooltip anchor="center left" self="center right" :offset="[5, 10]">
|
||||
<q-tooltip
|
||||
anchor="center left"
|
||||
self="center right"
|
||||
:offset="[5, 10]"
|
||||
>
|
||||
{{ $t("menuItems.copySeedWords") }}
|
||||
</q-tooltip>
|
||||
</q-btn>
|
||||
|
@ -68,7 +126,11 @@
|
|||
icon="file_copy"
|
||||
@click="copyPrivateKey('view_key', $event)"
|
||||
>
|
||||
<q-tooltip anchor="center left" self="center right" :offset="[5, 10]">
|
||||
<q-tooltip
|
||||
anchor="center left"
|
||||
self="center right"
|
||||
:offset="[5, 10]"
|
||||
>
|
||||
{{ $t("menuItems.copyViewKey") }}
|
||||
</q-tooltip>
|
||||
</q-btn>
|
||||
|
@ -91,7 +153,11 @@
|
|||
icon="file_copy"
|
||||
@click="copyPrivateKey('spend_key', $event)"
|
||||
>
|
||||
<q-tooltip anchor="center left" self="center right" :offset="[5, 10]">
|
||||
<q-tooltip
|
||||
anchor="center left"
|
||||
self="center right"
|
||||
:offset="[5, 10]"
|
||||
>
|
||||
{{ $t("menuItems.copySpendKey") }}
|
||||
</q-tooltip>
|
||||
</q-btn>
|
||||
|
@ -100,7 +166,11 @@
|
|||
</template>
|
||||
|
||||
<div class="q-mt-lg">
|
||||
<q-btn color="primary" :label="$t('buttons.close')" @click="hideModal('private_keys')" />
|
||||
<q-btn
|
||||
color="primary"
|
||||
:label="$t('buttons.close')"
|
||||
@click="hideModal('private_keys')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -108,50 +178,89 @@
|
|||
|
||||
<!-- RESCAN MODAL -->
|
||||
<q-dialog v-model="modals.rescan.visible" minimized>
|
||||
<div class="modal">
|
||||
<div class="modal rescan-modal">
|
||||
<div class="a-ma-lg modal-header">{{ $t("titles.rescanWallet") }}</div>
|
||||
<div class="q-ma-lg">
|
||||
<div class="q-ma-md">
|
||||
<p>{{ $t("strings.rescanModalDescription") }}</p>
|
||||
|
||||
<div class="q-mt-lg">
|
||||
<q-radio v-model="modals.rescan.type" val="full" :label="$t('fieldLabels.rescanFullBlockchain')" />
|
||||
<q-radio
|
||||
v-model="modals.rescan.type"
|
||||
val="full"
|
||||
:label="$t('fieldLabels.rescanFullBlockchain')"
|
||||
/>
|
||||
</div>
|
||||
<div class="q-mt-sm">
|
||||
<q-radio v-model="modals.rescan.type" val="spent" :label="$t('fieldLabels.rescanSpentOutputs')" />
|
||||
<q-radio
|
||||
v-model="modals.rescan.type"
|
||||
val="spent"
|
||||
:label="$t('fieldLabels.rescanSpentOutputs')"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="q-mt-xl text-right">
|
||||
<q-btn flat class="q-mr-sm" :label="$t('buttons.close')" @click="hideModal('rescan')" />
|
||||
<q-btn color="primary" :label="$t('buttons.rescan')" @click="rescanWallet()" />
|
||||
<q-btn
|
||||
flat
|
||||
class="q-mr-sm"
|
||||
:label="$t('buttons.close')"
|
||||
@click="hideModal('rescan')"
|
||||
/>
|
||||
<q-btn
|
||||
color="primary"
|
||||
:label="$t('buttons.rescan')"
|
||||
@click="rescanWallet()"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</q-dialog>
|
||||
|
||||
<!-- KEY IMAGE MODAL -->
|
||||
<q-dialog v-model="modals.key_image.visible" class="key-image-modal" minimized>
|
||||
<q-dialog
|
||||
v-model="modals.key_image.visible"
|
||||
class="key-image-modal"
|
||||
minimized
|
||||
>
|
||||
<div class="modal key-image-modal">
|
||||
<div class="modal-header">
|
||||
<!-- Export/Import key images -->
|
||||
{{
|
||||
$t("dialog.keyImages.title", {
|
||||
type: $t(`dialog.keyImages.${modals.key_image.type.toLowerCase()}`)
|
||||
type: $t(
|
||||
`dialog.keyImages.${modals.key_image.type.toLowerCase()}`
|
||||
)
|
||||
})
|
||||
}}
|
||||
</div>
|
||||
<div class="q-ma-lg">
|
||||
<div class="q-ma-md">
|
||||
<div class="row q-mb-md">
|
||||
<div class="q-mr-xl">
|
||||
<q-radio v-model="modals.key_image.type" val="Export" :label="$t('dialog.keyImages.export')" />
|
||||
<q-radio
|
||||
v-model="modals.key_image.type"
|
||||
val="Export"
|
||||
:label="$t('dialog.keyImages.export')"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<q-radio v-model="modals.key_image.type" val="Import" :label="$t('dialog.keyImages.import')" />
|
||||
<q-radio
|
||||
v-model="modals.key_image.type"
|
||||
val="Import"
|
||||
:label="$t('dialog.keyImages.import')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template v-if="modals.key_image.type == 'Export'">
|
||||
<LokiField class="q-mt-lg" :label="$t('fieldLabels.keyImages.exportDirectory')" disable-hover>
|
||||
<q-input v-model="modals.key_image.export_path" disable borderless />
|
||||
<OxenField
|
||||
class="q-mt-lg"
|
||||
:label="$t('fieldLabels.keyImages.exportDirectory')"
|
||||
disable-hover
|
||||
>
|
||||
<q-input
|
||||
v-model="modals.key_image.export_path"
|
||||
disable
|
||||
borderless
|
||||
/>
|
||||
<input
|
||||
id="keyImageExportPath"
|
||||
ref="keyImageExportSelect"
|
||||
|
@ -162,12 +271,22 @@
|
|||
hidden
|
||||
@change="setKeyImageExportPath"
|
||||
/>
|
||||
<q-btn color="secondary" @click="selectKeyImageExportPath">{{ $t("buttons.browse") }}</q-btn>
|
||||
</LokiField>
|
||||
<q-btn color="primary" @click="selectKeyImageExportPath">{{
|
||||
$t("buttons.browse")
|
||||
}}</q-btn>
|
||||
</OxenField>
|
||||
</template>
|
||||
<template v-if="modals.key_image.type == 'Import'">
|
||||
<LokiField class="q-mt-lg" :label="$t('fieldLabels.keyImages.importFile')" disable-hover>
|
||||
<q-input v-model="modals.key_image.import_path" disable borderless />
|
||||
<OxenField
|
||||
class="q-mt-lg"
|
||||
:label="$t('fieldLabels.keyImages.importFile')"
|
||||
disable-hover
|
||||
>
|
||||
<q-input
|
||||
v-model="modals.key_image.import_path"
|
||||
disable
|
||||
borderless
|
||||
/>
|
||||
<input
|
||||
id="keyImageImportPath"
|
||||
ref="keyImageImportSelect"
|
||||
|
@ -176,12 +295,19 @@
|
|||
hidden
|
||||
@change="setKeyImageImportPath"
|
||||
/>
|
||||
<q-btn color="secondary" @click="selectKeyImageImportPath">{{ $t("buttons.browse") }}</q-btn>
|
||||
</LokiField>
|
||||
<q-btn color="primary" @click="selectKeyImageImportPath">{{
|
||||
$t("buttons.browse")
|
||||
}}</q-btn>
|
||||
</OxenField>
|
||||
</template>
|
||||
|
||||
<div class="q-mt-lg text-right">
|
||||
<q-btn flat class="q-mr-sm" :label="$t('buttons.close')" @click="hideModal('key_image')" />
|
||||
<q-btn
|
||||
flat
|
||||
class="q-mr-sm"
|
||||
:label="$t('buttons.close')"
|
||||
@click="hideModal('key_image')"
|
||||
/>
|
||||
<q-btn
|
||||
color="primary"
|
||||
:label="$t('buttons.' + modals.key_image.type.toLowerCase())"
|
||||
|
@ -193,33 +319,98 @@
|
|||
</q-dialog>
|
||||
|
||||
<!-- CHANGE PASSWORD MODAL -->
|
||||
<q-dialog v-model="modals.change_password.visible" minimized @hide="clearChangePassword()">
|
||||
<q-dialog
|
||||
v-model="modals.change_password.visible"
|
||||
minimized
|
||||
@hide="clearChangePassword()"
|
||||
>
|
||||
<div class="modal password-modal">
|
||||
<div class="modal-header">{{ $t("titles.changePassword") }}</div>
|
||||
<div class="q-ma-lg">
|
||||
<div class="q-ma-md">
|
||||
<q-input
|
||||
v-model="modals.change_password.old_password"
|
||||
type="password"
|
||||
:label="$t('fieldLabels.oldPassword')"
|
||||
:dark="theme == 'dark'"
|
||||
/>
|
||||
<q-input
|
||||
v-model="modals.change_password.new_password"
|
||||
type="password"
|
||||
:label="$t('fieldLabels.newPassword')"
|
||||
:dark="theme == 'dark'"
|
||||
/>
|
||||
|
||||
<q-input
|
||||
v-model="modals.change_password.new_password_confirm"
|
||||
type="password"
|
||||
:label="$t('fieldLabels.confirmNewPassword')"
|
||||
:dark="theme == 'dark'"
|
||||
/>
|
||||
|
||||
<div class="q-mt-xl text-right">
|
||||
<q-btn flat class="q-mr-sm" :label="$t('buttons.close')" @click="hideModal('change_password')" />
|
||||
<q-btn color="primary" :label="$t('buttons.change')" @click="doChangePassword()" />
|
||||
<q-btn
|
||||
flat
|
||||
class="q-mr-sm"
|
||||
:label="$t('buttons.close')"
|
||||
@click="hideModal('change_password')"
|
||||
/>
|
||||
<q-btn
|
||||
color="primary"
|
||||
:label="$t('buttons.change')"
|
||||
@click="doChangePassword()"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</q-dialog>
|
||||
<!-- EXPORT TRANSFERS MODAL -->
|
||||
<q-dialog
|
||||
v-model="modals.export_transfers.visible"
|
||||
class="export-transfers-modal"
|
||||
minimized
|
||||
>
|
||||
<div class="modal export-transfers-modal">
|
||||
<div class="modal-header">
|
||||
<!-- Export Transfers as CSV -->
|
||||
{{ $t("dialog.exportTransfers.title") }}
|
||||
</div>
|
||||
<div class="q-ma-md">
|
||||
<template>
|
||||
<OxenField
|
||||
class="q-mt-lg"
|
||||
:label="$t('fieldLabels.exportTransfers.exportDirectory')"
|
||||
disable-hover
|
||||
>
|
||||
<q-input
|
||||
v-model="modals.export_transfers.export_path"
|
||||
disable
|
||||
borderless
|
||||
/>
|
||||
<input
|
||||
id="exportTransfersExportPath"
|
||||
ref="exportTransfersExportSelect"
|
||||
class="export-transfers-path"
|
||||
type="file"
|
||||
webkitdirectory
|
||||
directory
|
||||
hidden
|
||||
@change="setExportTransfersExportPath"
|
||||
/>
|
||||
<q-btn color="primary" @click="selectExportTransfersExportPath">{{
|
||||
$t("buttons.browse")
|
||||
}}</q-btn>
|
||||
</OxenField>
|
||||
</template>
|
||||
|
||||
<div class="q-mt-lg text-right">
|
||||
<q-btn
|
||||
flat
|
||||
class="q-mr-sm"
|
||||
:label="$t('buttons.close')"
|
||||
@click="hideModal('export_transfers')"
|
||||
/>
|
||||
<q-btn
|
||||
color="primary"
|
||||
:label="$t('buttons.export')"
|
||||
@click="doExportTransfers()"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -231,12 +422,12 @@
|
|||
const { clipboard } = require("electron");
|
||||
import { mapState } from "vuex";
|
||||
import WalletPassword from "src/mixins/wallet_password";
|
||||
import LokiField from "components/loki_field";
|
||||
import OxenField from "components/oxen_field";
|
||||
|
||||
export default {
|
||||
name: "WalletSettings",
|
||||
components: {
|
||||
LokiField
|
||||
OxenField
|
||||
},
|
||||
mixins: [WalletPassword],
|
||||
data() {
|
||||
|
@ -255,6 +446,10 @@ export default {
|
|||
export_path: "",
|
||||
import_path: ""
|
||||
},
|
||||
export_transfers: {
|
||||
visible: false,
|
||||
export_path: ""
|
||||
},
|
||||
change_password: {
|
||||
visible: false,
|
||||
old_password: "",
|
||||
|
@ -307,8 +502,22 @@ export default {
|
|||
},
|
||||
created() {
|
||||
const path = require("upath");
|
||||
this.modals.key_image.export_path = path.join(this.wallet_data_dir, "images", this.info.name);
|
||||
this.modals.key_image.import_path = path.join(this.wallet_data_dir, "images", this.info.name, "key_image_export");
|
||||
this.modals.key_image.export_path = path.join(
|
||||
this.wallet_data_dir,
|
||||
"images",
|
||||
this.info.name
|
||||
);
|
||||
this.modals.key_image.import_path = path.join(
|
||||
this.wallet_data_dir,
|
||||
"images",
|
||||
this.info.name,
|
||||
"key_image_export"
|
||||
);
|
||||
this.modals.export_transfers.export_path = path.join(
|
||||
this.wallet_data_dir,
|
||||
"CSV",
|
||||
this.info.name
|
||||
);
|
||||
},
|
||||
methods: {
|
||||
showModal(which) {
|
||||
|
@ -355,8 +564,7 @@ export default {
|
|||
ok: {
|
||||
label: this.$t("dialog.buttons.ok"),
|
||||
color: "primary"
|
||||
},
|
||||
dark: this.theme === "dark"
|
||||
}
|
||||
})
|
||||
.onDismiss(() => null)
|
||||
.onCancel(() => null)
|
||||
|
@ -379,8 +587,11 @@ export default {
|
|||
label: this.$t("dialog.showPrivateKeys.ok"),
|
||||
color: "primary"
|
||||
},
|
||||
dark: this.theme == "dark",
|
||||
color: this.theme == "dark" ? "white" : "dark"
|
||||
cancel: {
|
||||
color: "tertiary",
|
||||
flat: true
|
||||
},
|
||||
color: "white"
|
||||
});
|
||||
passwordDialog
|
||||
.onOk(password => {
|
||||
|
@ -418,10 +629,8 @@ export default {
|
|||
},
|
||||
cancel: {
|
||||
flat: true,
|
||||
label: this.$t("dialog.buttons.cancel"),
|
||||
color: this.theme == "dark" ? "white" : "dark"
|
||||
},
|
||||
dark: this.theme == "dark"
|
||||
label: this.$t("dialog.buttons.cancel")
|
||||
}
|
||||
})
|
||||
.onOk(() => {
|
||||
this.$gateway.send("wallet", "rescan_blockchain");
|
||||
|
@ -444,10 +653,18 @@ export default {
|
|||
setKeyImageImportPath(file) {
|
||||
this.modals.key_image.import_path = file.target.files[0].path;
|
||||
},
|
||||
selectExportTransfersExportPath() {
|
||||
this.$refs.exportTransfersExportSelect.click();
|
||||
},
|
||||
setExportTransfersExportPath(file) {
|
||||
this.modals.export_transfers.export_path = file.target.files[0].path;
|
||||
},
|
||||
async doKeyImages() {
|
||||
this.hideModal("key_image");
|
||||
|
||||
const type = this.$t(`dialog.keyImages.${this.modals.key_image.type.toLowerCase()}`);
|
||||
const type = this.$t(
|
||||
`dialog.keyImages.${this.modals.key_image.type.toLowerCase()}`
|
||||
);
|
||||
|
||||
let passwordDialog = await this.showPasswordConfirmation({
|
||||
title: this.$t("dialog.keyImages.title", { type }),
|
||||
|
@ -458,8 +675,11 @@ export default {
|
|||
label: type.toLocaleUpperCase(this.locale),
|
||||
color: "primary"
|
||||
},
|
||||
dark: this.theme == "dark",
|
||||
color: this.theme == "dark" ? "white" : "dark"
|
||||
color: this.theme == "dark" ? "dark" : "white",
|
||||
cancel: {
|
||||
color: "tertiary",
|
||||
flat: true
|
||||
}
|
||||
});
|
||||
passwordDialog
|
||||
.onOk(password => {
|
||||
|
@ -482,7 +702,8 @@ export default {
|
|||
doChangePassword() {
|
||||
let old_password = this.modals.change_password.old_password;
|
||||
let new_password = this.modals.change_password.new_password;
|
||||
let new_password_confirm = this.modals.change_password.new_password_confirm;
|
||||
let new_password_confirm = this.modals.change_password
|
||||
.new_password_confirm;
|
||||
|
||||
if (new_password == old_password) {
|
||||
this.$q.notify({
|
||||
|
@ -509,6 +730,34 @@ export default {
|
|||
this.modals.change_password.new_password = "";
|
||||
this.modals.change_password.new_password_confirm = "";
|
||||
},
|
||||
async doExportTransfers() {
|
||||
this.hideModal("export_transfers");
|
||||
|
||||
let passwordDialog = await this.showPasswordConfirmation({
|
||||
title: this.$t("dialog.exportTransfers.title"),
|
||||
noPasswordMessage: this.$t("dialog.exportTransfers.message"),
|
||||
ok: {
|
||||
label: "export".toLocaleUpperCase(this.locale),
|
||||
color: "primary"
|
||||
},
|
||||
color: this.theme == "dark" ? "dark" : "white",
|
||||
cancel: {
|
||||
color: "tertiary",
|
||||
flat: true
|
||||
}
|
||||
});
|
||||
passwordDialog
|
||||
.onOk(password => {
|
||||
// if no password set
|
||||
password = password || "";
|
||||
this.$gateway.send("wallet", "export_transfers", {
|
||||
password: password,
|
||||
path: this.modals.export_transfers.export_path
|
||||
});
|
||||
})
|
||||
.onCancel(() => {})
|
||||
.onDismiss(() => {});
|
||||
},
|
||||
deleteWallet() {
|
||||
if (!this.is_ready) return;
|
||||
this.$q
|
||||
|
@ -524,7 +773,7 @@ export default {
|
|||
label: this.$t("dialog.buttons.cancel"),
|
||||
color: this.theme == "dark" ? "white" : "dark"
|
||||
},
|
||||
dark: this.theme == "dark"
|
||||
color: "#1F1C47"
|
||||
})
|
||||
.onOk(async () => {
|
||||
const hasPassword = await this.hasPassword();
|
||||
|
@ -569,17 +818,20 @@ export default {
|
|||
};
|
||||
</script>
|
||||
|
||||
.menu-list { }
|
||||
|
||||
<style lang="scss">
|
||||
.wallet-settings {
|
||||
.q-btn {
|
||||
color: white;
|
||||
.password-modal {
|
||||
min-width: 400px;
|
||||
background: white;
|
||||
color: #1f1c47;
|
||||
|
||||
> * {
|
||||
color: #1f1c47;
|
||||
}
|
||||
}
|
||||
|
||||
.password-modal {
|
||||
min-width: 400px;
|
||||
.rescan-modal {
|
||||
background: white;
|
||||
color: #1f1c47;
|
||||
}
|
||||
|
||||
.image-path {
|
||||
|
@ -588,8 +840,25 @@ export default {
|
|||
}
|
||||
|
||||
.key-image-modal {
|
||||
color: #1f1c47;
|
||||
background: white;
|
||||
|
||||
label * {
|
||||
color: #cecece !important;
|
||||
color: #1f1c47 !important;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
input {
|
||||
overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
.export-transfers-modal {
|
||||
color: #1f1c47;
|
||||
background: white;
|
||||
min-width: 500px;
|
||||
|
||||
label * {
|
||||
color: #1f1c47 !important;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
@ -598,7 +867,15 @@ export default {
|
|||
}
|
||||
}
|
||||
|
||||
.export-transfers-path {
|
||||
opacity: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.private-key-modal {
|
||||
background: white;
|
||||
color: #1f1c47;
|
||||
|
||||
.copy-btn {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
@ -608,7 +885,7 @@ export default {
|
|||
min-width: 400px;
|
||||
width: 45vw;
|
||||
|
||||
.loki-field {
|
||||
.oxen-field {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div class="lns-input">
|
||||
<LNSInputForm
|
||||
<div class="ons-input">
|
||||
<ONSInputForm
|
||||
ref="form"
|
||||
:submit-label="submit_label"
|
||||
:disable-name="updating || renewing"
|
||||
|
@ -11,7 +11,7 @@
|
|||
@onSubmit="onSubmit"
|
||||
@onClear="onClear"
|
||||
/>
|
||||
<q-inner-loading :showing="lns_status.sending" :dark="theme == 'dark'">
|
||||
<q-inner-loading :showing="ons_status.sending" :dark="theme == 'dark'">
|
||||
<q-spinner color="primary" size="30" />
|
||||
</q-inner-loading>
|
||||
</div>
|
||||
|
@ -19,14 +19,14 @@
|
|||
|
||||
<script>
|
||||
import { mapState } from "vuex";
|
||||
import LNSInputForm from "./lns_input_form";
|
||||
import ONSInputForm from "./ons_input_form";
|
||||
import WalletPassword from "src/mixins/wallet_password";
|
||||
const objectAssignDeep = require("object-assign-deep");
|
||||
|
||||
export default {
|
||||
name: "LNSInput",
|
||||
name: "ONSInput",
|
||||
components: {
|
||||
LNSInputForm
|
||||
ONSInputForm
|
||||
},
|
||||
mixins: [WalletPassword],
|
||||
data() {
|
||||
|
@ -37,10 +37,10 @@ export default {
|
|||
},
|
||||
computed: mapState({
|
||||
theme: state => state.gateway.app.config.appearance.theme,
|
||||
lns_status: state => state.gateway.lns_status,
|
||||
ons_status: state => state.gateway.ons_status,
|
||||
unlocked_balance: state => state.gateway.wallet.info.unlocked_balance,
|
||||
disable_submit_button() {
|
||||
const minBalance = this.updating ? 0.05 : 21;
|
||||
const minBalance = this.updating ? 0.05 : 7.1;
|
||||
return this.unlocked_balance < minBalance * 1e9;
|
||||
},
|
||||
submit_label() {
|
||||
|
@ -55,7 +55,7 @@ export default {
|
|||
}),
|
||||
|
||||
watch: {
|
||||
lns_status: {
|
||||
ons_status: {
|
||||
handler(val, old) {
|
||||
if (val.code == old.code) return;
|
||||
const { code, message } = val;
|
||||
|
@ -119,28 +119,27 @@ export default {
|
|||
};
|
||||
|
||||
let passwordDialog = await this.showPasswordConfirmation({
|
||||
title: this.$t("dialog.lnsUpdate.title"),
|
||||
noPasswordMessage: this.$t("dialog.lnsUpdate.message"),
|
||||
title: this.$t("dialog.onsUpdate.title"),
|
||||
noPasswordMessage: this.$t("dialog.onsUpdate.message"),
|
||||
ok: {
|
||||
label: this.$t("dialog.lnsUpdate.ok"),
|
||||
label: this.$t("dialog.onsUpdate.ok"),
|
||||
color: "primary"
|
||||
},
|
||||
dark: this.theme == "dark",
|
||||
color: this.theme == "dark" ? "white" : "dark"
|
||||
color: "#1F1C47"
|
||||
});
|
||||
passwordDialog
|
||||
.onOk(password => {
|
||||
// if no password set
|
||||
password = password || "";
|
||||
this.$store.commit("gateway/set_lns_status", {
|
||||
this.$store.commit("gateway/set_ons_status", {
|
||||
code: 1,
|
||||
message: "Sending transaction",
|
||||
sending: true
|
||||
});
|
||||
const lns = objectAssignDeep.noMutate(updatedRecord, {
|
||||
const ons = objectAssignDeep.noMutate(updatedRecord, {
|
||||
password
|
||||
});
|
||||
this.$gateway.send("wallet", "update_lns_mapping", lns);
|
||||
this.$gateway.send("wallet", "update_ons_mapping", ons);
|
||||
})
|
||||
.onDismiss(() => {})
|
||||
.onCancel(() => {});
|
||||
|
@ -152,23 +151,21 @@ export default {
|
|||
ok: {
|
||||
label: this.$t("dialog.purchase.ok"),
|
||||
color: "primary"
|
||||
},
|
||||
dark: this.theme == "dark",
|
||||
color: this.theme == "dark" ? "white" : "dark"
|
||||
}
|
||||
});
|
||||
passwordDialog
|
||||
.onOk(password => {
|
||||
// if no password set
|
||||
password = password || "";
|
||||
this.$store.commit("gateway/set_lns_status", {
|
||||
this.$store.commit("gateway/set_ons_status", {
|
||||
code: 1,
|
||||
message: "Sending transaction",
|
||||
sending: true
|
||||
});
|
||||
const lns = objectAssignDeep.noMutate(record, {
|
||||
const ons = objectAssignDeep.noMutate(record, {
|
||||
password
|
||||
});
|
||||
this.$gateway.send("wallet", "purchase_lns", lns);
|
||||
this.$gateway.send("wallet", "purchase_ons", ons);
|
||||
})
|
||||
.onDismiss(() => {})
|
||||
.onCancel(() => {});
|
||||
|
@ -188,7 +185,7 @@ export default {
|
|||
.onOk(password => {
|
||||
// if no password set
|
||||
password = password || "";
|
||||
this.$store.commit("gateway/set_lns_status", {
|
||||
this.$store.commit("gateway/set_ons_status", {
|
||||
code: 1,
|
||||
message: "Sending renew mapping transaction",
|
||||
sending: true
|
||||
|
@ -198,7 +195,7 @@ export default {
|
|||
name: record.name,
|
||||
password
|
||||
};
|
||||
this.$gateway.send("wallet", "lns_renew_mapping", params);
|
||||
this.$gateway.send("wallet", "ons_renew_mapping", params);
|
||||
})
|
||||
.onDismiss(() => {})
|
||||
.onCancel(() => {});
|
|
@ -1,23 +1,22 @@
|
|||
<template>
|
||||
<div class="lns-input-form">
|
||||
<div class="ons-input-form">
|
||||
<!-- Type -->
|
||||
<div class="col q-mt-sm">
|
||||
<LokiField :label="$t('fieldLabels.lnsType')" :disable="updating">
|
||||
<OxenField :label="$t('fieldLabels.onsType')" :disable="updating">
|
||||
<q-select
|
||||
v-model.trim="record.type"
|
||||
emit-value
|
||||
map-options
|
||||
:options="renewing ? lokinetOptions : typeOptions"
|
||||
:dark="theme == 'dark'"
|
||||
:disable="updating"
|
||||
borderless
|
||||
dense
|
||||
/>
|
||||
</LokiField>
|
||||
</OxenField>
|
||||
</div>
|
||||
<!-- Name -->
|
||||
<div class="col q-mt-sm">
|
||||
<LokiField
|
||||
<OxenField
|
||||
:label="$t('fieldLabels.name')"
|
||||
:disable="disableName"
|
||||
:error="$v.record.name.$error"
|
||||
|
@ -25,19 +24,21 @@
|
|||
<q-input
|
||||
v-model.trim="record.name"
|
||||
:dark="theme == 'dark'"
|
||||
:placeholder="$t('placeholders.lnsName')"
|
||||
:placeholder="$t('placeholders.onsName')"
|
||||
:disable="disableName"
|
||||
borderless
|
||||
dense
|
||||
:suffix="record.type === 'session' ? '' : '.loki'"
|
||||
:suffix="
|
||||
record.type === 'session' || record.type === 'wallet' ? '' : '.loki'
|
||||
"
|
||||
@blur="$v.record.name.$touch"
|
||||
/>
|
||||
</LokiField>
|
||||
</OxenField>
|
||||
</div>
|
||||
|
||||
<!-- Value (Session ID, Wallet Address or .loki address) -->
|
||||
<div class="col q-mt-sm">
|
||||
<LokiField
|
||||
<OxenField
|
||||
class="q-mt-md"
|
||||
:label="value_field_label"
|
||||
:error="$v.record.value.$error"
|
||||
|
@ -49,15 +50,17 @@
|
|||
borderless
|
||||
dense
|
||||
:disable="renewing"
|
||||
:suffix="record.type === 'session' ? '' : '.loki'"
|
||||
:suffix="
|
||||
record.type === 'session' || record.type === 'wallet' ? '' : '.loki'
|
||||
"
|
||||
@blur="$v.record.value.$touch"
|
||||
/>
|
||||
</LokiField>
|
||||
</OxenField>
|
||||
</div>
|
||||
|
||||
<!-- Owner -->
|
||||
<div class="col q-mt-sm">
|
||||
<LokiField
|
||||
<OxenField
|
||||
class="q-mt-md"
|
||||
:label="$t('fieldLabels.owner')"
|
||||
:error="$v.record.owner.$error"
|
||||
|
@ -72,12 +75,12 @@
|
|||
:disable="renewing"
|
||||
@blur="$v.record.owner.$touch"
|
||||
/>
|
||||
</LokiField>
|
||||
</OxenField>
|
||||
</div>
|
||||
|
||||
<!-- Backup owner -->
|
||||
<div class="col q-mt-sm">
|
||||
<LokiField
|
||||
<OxenField
|
||||
class="q-mt-md"
|
||||
:label="$t('fieldLabels.backupOwner')"
|
||||
:error="$v.record.backup_owner.$error"
|
||||
|
@ -86,13 +89,13 @@
|
|||
<q-input
|
||||
v-model.trim="record.backup_owner"
|
||||
:dark="theme == 'dark'"
|
||||
:placeholder="$t('placeholders.lnsBackupOwner')"
|
||||
:placeholder="$t('placeholders.onsBackupOwner')"
|
||||
:disable="renewing"
|
||||
borderless
|
||||
dense
|
||||
@blur="$v.record.backup_owner.$touch"
|
||||
/>
|
||||
</LokiField>
|
||||
</OxenField>
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<q-btn
|
||||
|
@ -103,7 +106,7 @@
|
|||
/>
|
||||
<q-btn
|
||||
v-if="showClearButton"
|
||||
color="secondary"
|
||||
color="accent"
|
||||
:label="$t('buttons.clear')"
|
||||
@click="clear()"
|
||||
/>
|
||||
|
@ -120,13 +123,13 @@ import {
|
|||
lokinet_name,
|
||||
session_name
|
||||
} from "src/validators/common";
|
||||
import LokiField from "components/loki_field";
|
||||
import OxenField from "components/oxen_field";
|
||||
import WalletPassword from "src/mixins/wallet_password";
|
||||
|
||||
export default {
|
||||
name: "LNSInputForm",
|
||||
name: "ONSInputForm",
|
||||
components: {
|
||||
LokiField
|
||||
OxenField
|
||||
},
|
||||
mixins: [WalletPassword],
|
||||
props: {
|
||||
|
@ -166,28 +169,31 @@ export default {
|
|||
},
|
||||
data() {
|
||||
let sessionOptions = [
|
||||
{ label: this.$t("strings.lns.sessionID"), value: "session" }
|
||||
{ label: this.$t("strings.ons.sessionID"), value: "session" }
|
||||
];
|
||||
let walletOptions = [
|
||||
{ label: this.$t("strings.ons.wallet"), value: "wallet" }
|
||||
];
|
||||
let lokinetOptions = [
|
||||
{ label: this.$t("strings.lns.lokinetName1Year"), value: "lokinet_1y" },
|
||||
{ label: this.$t("strings.ons.lokinetName1Year"), value: "lokinet_1y" },
|
||||
{
|
||||
label: this.$t("strings.lns.lokinetNameXYears", { years: 2 }),
|
||||
label: this.$t("strings.ons.lokinetNameXYears", { years: 2 }),
|
||||
value: "lokinet_2y"
|
||||
},
|
||||
{
|
||||
label: this.$t("strings.lns.lokinetNameXYears", { years: 5 }),
|
||||
label: this.$t("strings.ons.lokinetNameXYears", { years: 5 }),
|
||||
value: "lokinet_5y"
|
||||
},
|
||||
{
|
||||
label: this.$t("strings.lns.lokinetNameXYears", { years: 10 }),
|
||||
label: this.$t("strings.ons.lokinetNameXYears", { years: 10 }),
|
||||
value: "lokinet_10y"
|
||||
}
|
||||
];
|
||||
let typeOptions = [...sessionOptions, ...lokinetOptions];
|
||||
let typeOptions = [...sessionOptions, ...walletOptions, ...lokinetOptions];
|
||||
|
||||
const initialRecord = {
|
||||
// Lokinet 1 year is valid on renew or purchase
|
||||
type: typeOptions[1].value,
|
||||
type: typeOptions[2].value,
|
||||
name: "",
|
||||
value: "",
|
||||
owner: "",
|
||||
|
@ -208,6 +214,8 @@ export default {
|
|||
value_field_label() {
|
||||
if (this.record.type === "session") {
|
||||
return this.$t("fieldLabels.sessionId");
|
||||
} else if (this.record.type === "wallet") {
|
||||
return this.$t("fieldLabels.walletAddress");
|
||||
} else {
|
||||
return this.$t("fieldLabels.lokinetFullAddress");
|
||||
}
|
||||
|
@ -232,6 +240,8 @@ export default {
|
|||
value_placeholder() {
|
||||
if (this.record.type === "session") {
|
||||
return this.$t("placeholders.sessionId");
|
||||
} else if (this.record.type === "wallet") {
|
||||
return this.$t("placeholders.walletAddress");
|
||||
} else {
|
||||
return this.$t("placeholders.lokinetFullAddress");
|
||||
}
|
||||
|
@ -334,7 +344,10 @@ export default {
|
|||
const submitRecord = {
|
||||
...this.record,
|
||||
name: this.record.name.toLowerCase(),
|
||||
value: this.record.value.toLowerCase()
|
||||
value:
|
||||
this.record.type === "wallet"
|
||||
? this.record.value
|
||||
: this.record.value.toLowerCase()
|
||||
};
|
||||
// Send up the submission with the record
|
||||
this.$emit("onSubmit", submitRecord);
|
||||
|
@ -357,7 +370,7 @@ export default {
|
|||
if (this.record.type === "session") {
|
||||
return session_name(_value);
|
||||
} else {
|
||||
// shortened lokinet LNS name
|
||||
// shortened lokinet ONS name
|
||||
return lokinet_name(_value);
|
||||
}
|
||||
}
|
||||
|
@ -373,6 +386,8 @@ export default {
|
|||
const _value = value.toLowerCase();
|
||||
if (this.record.type === "session") {
|
||||
return session_id(_value);
|
||||
} else if (this.record.type === "wallet") {
|
||||
return this.isAddress(value);
|
||||
} else {
|
||||
// full lokinet address
|
||||
return lokinet_address(_value);
|
||||
|
@ -390,7 +405,7 @@ export default {
|
|||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.lns-input-form {
|
||||
.ons-input-form {
|
||||
.buttons {
|
||||
margin-top: 6px;
|
||||
|
|
@ -1,21 +1,21 @@
|
|||
<template>
|
||||
<div class="my-lns">
|
||||
<div class="my-ons">
|
||||
<div class="q-px-md q-pt-md">
|
||||
<div class="description">
|
||||
{{ $t("strings.lnsDescription") }}
|
||||
<div class="tab-desc">
|
||||
{{ $t("strings.onsDescription") }}
|
||||
</div>
|
||||
<LNSRecords @onUpdate="onUpdate" @onRenew="onRenew" />
|
||||
<ONSRecords @onUpdate="onUpdate" @onRenew="onRenew" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import LNSRecords from "./lns_records";
|
||||
import ONSRecords from "./ons_records";
|
||||
|
||||
export default {
|
||||
name: "MyLNS",
|
||||
name: "MyONS",
|
||||
components: {
|
||||
LNSRecords
|
||||
ONSRecords
|
||||
},
|
||||
methods: {
|
||||
onUpdate(record) {
|
||||
|
@ -29,7 +29,7 @@ export default {
|
|||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.my-lns {
|
||||
.my-ons {
|
||||
.description {
|
||||
white-space: pre-line;
|
||||
color: #cecece;
|
|
@ -0,0 +1,72 @@
|
|||
<template>
|
||||
<div class="ons-purchase">
|
||||
<div class="q-mb-lg q-px-md q-pt-md">
|
||||
<div class="tab-desc">
|
||||
{{ $t("strings.onsPurchaseDescription") }}
|
||||
</div>
|
||||
<div class="prices">
|
||||
{{ $t("strings.ons.prices") }}
|
||||
<table>
|
||||
<tr>
|
||||
<td>{{ $t("strings.ons.sessionID") }}:</td>
|
||||
<td>7 OXEN</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t("strings.ons.wallet") }}:</td>
|
||||
<td>7 OXEN</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t("strings.ons.lokinetName1Year") }}:</td>
|
||||
<td>7 OXEN</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t("strings.ons.lokinetNameXYears", { years: 2 }) }}:</td>
|
||||
<td>14 OXEN</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t("strings.ons.lokinetNameXYears", { years: 5 }) }}:</td>
|
||||
<td>28 OXEN</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t("strings.ons.lokinetNameXYears", { years: 10 }) }}:</td>
|
||||
<td>42 OXEN</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<ONSInput ref="input" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ONSInput from "./ons_input";
|
||||
export default {
|
||||
name: "ONSPurchase",
|
||||
components: {
|
||||
ONSInput
|
||||
},
|
||||
methods: {
|
||||
startUpdating(record) {
|
||||
this.$refs.input.startUpdating(record);
|
||||
},
|
||||
startRenewing(record) {
|
||||
this.$refs.input.startRenewing(record);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.ons-purchase {
|
||||
.description {
|
||||
white-space: pre-line;
|
||||
// oxen-navy
|
||||
color: #1f1c47;
|
||||
}
|
||||
|
||||
.prices {
|
||||
// oxen-navy
|
||||
margin-top: 20px;
|
||||
color: #1f1c47;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,9 +1,9 @@
|
|||
<template>
|
||||
<q-list link no-border :dark="theme == 'dark'" class="lns-record-list">
|
||||
<q-list link no-border class="ons-record-list">
|
||||
<q-item
|
||||
v-for="record in recordList"
|
||||
:key="record.name_hash"
|
||||
class="loki-list-item"
|
||||
class="oxen-list-item"
|
||||
>
|
||||
<q-item-section class="type" avatar>
|
||||
<q-icon :name="isLocked(record) ? 'lock' : 'lock_open'" size="24px" />
|
||||
|
@ -12,7 +12,9 @@
|
|||
<q-item-label :class="bindClass(record)">{{
|
||||
isLocked(record) ? record.name_hash : record.name
|
||||
}}</q-item-label>
|
||||
<q-item-label v-if="!isLocked(record)">{{ record.value }}</q-item-label>
|
||||
<q-item-label v-if="!isLocked(record)" class="truncate-item">{{
|
||||
record.value
|
||||
}}</q-item-label>
|
||||
</q-item-section>
|
||||
<q-item-section side class="height">
|
||||
<template v-if="isLocked(record)">{{
|
||||
|
@ -22,13 +24,13 @@
|
|||
<q-item-section>
|
||||
<div class="row update-renew-buttons">
|
||||
<q-btn
|
||||
color="secondary"
|
||||
color="primary"
|
||||
:label="$t('buttons.update')"
|
||||
@click="onUpdate(record)"
|
||||
/>
|
||||
<q-btn
|
||||
v-if="isLokinet"
|
||||
color="secondary"
|
||||
color="primary"
|
||||
:label="$t('buttons.renew')"
|
||||
@click="onRenew(record)"
|
||||
/>
|
||||
|
@ -37,7 +39,7 @@
|
|||
</template>
|
||||
</q-item-section>
|
||||
<q-item-section v-if="!isLocked(record)" side>
|
||||
<span v-if="record.type === 'session'">{{
|
||||
<span v-if="record.type === 'session' || record.type === 'wallet'">{{
|
||||
record.update_height | blockHeight
|
||||
}}</span>
|
||||
<span v-else class="lokinet-expiration">{{
|
||||
|
@ -67,7 +69,7 @@ import ContextMenu from "components/menus/contextmenu";
|
|||
const { clipboard } = require("electron");
|
||||
|
||||
export default {
|
||||
name: "LNSRecordList",
|
||||
name: "ONSRecordList",
|
||||
components: {
|
||||
ContextMenu
|
||||
},
|
||||
|
@ -108,7 +110,7 @@ export default {
|
|||
this.$emit("onRenew", record);
|
||||
},
|
||||
copyNameI18nLabel(record) {
|
||||
if (record.type === "session") {
|
||||
if (record.type === "session" || record.type === "wallet") {
|
||||
return "menuItems.copyName";
|
||||
} else {
|
||||
return "menuItems.copyLokinetName";
|
||||
|
@ -146,6 +148,9 @@ export default {
|
|||
if (record.type === "session") {
|
||||
message = this.$t("notification.positive.sessionIdCopied");
|
||||
}
|
||||
if (record.type === "wallet") {
|
||||
message = this.$t("notification.positive.walletCopied");
|
||||
}
|
||||
this.copy(record.value, message);
|
||||
},
|
||||
copy(value, message) {
|
||||
|
@ -161,36 +166,4 @@ export default {
|
|||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.lokinet-expiration {
|
||||
width: 180px;
|
||||
}
|
||||
|
||||
.lns-record-list {
|
||||
.q-item {
|
||||
cursor: pointer;
|
||||
background: #313131;
|
||||
-webkit-transition: background-color 0.2s ease-in;
|
||||
transition: background-color 0.2s ease-in;
|
||||
|
||||
border-radius: 3px;
|
||||
|
||||
+ .q-item {
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.q-item-sublabel {
|
||||
color: #313131;
|
||||
}
|
||||
|
||||
.q-item:hover {
|
||||
background: rgba(117, 117, 117, 0.3);
|
||||
}
|
||||
}
|
||||
.update-renew-buttons {
|
||||
.q-btn:not(:first-child) {
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style lang="scss"></style>
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div class="lns-record-list">
|
||||
<div class="ons-record-list">
|
||||
<div v-if="needsDecryption" class="decrypt row justify-between items-end">
|
||||
<LokiField
|
||||
<OxenField
|
||||
:label="$t('fieldLabels.decryptRecord')"
|
||||
:disable="decrypting"
|
||||
:error="$v.name.$error"
|
||||
|
@ -11,11 +11,11 @@
|
|||
:dark="theme == 'dark'"
|
||||
borderless
|
||||
dense
|
||||
:placeholder="$t('placeholders.lnsDecryptName')"
|
||||
:placeholder="$t('placeholders.onsDecryptName')"
|
||||
:disable="decrypting"
|
||||
@blur="$v.name.$touch"
|
||||
/>
|
||||
</LokiField>
|
||||
</OxenField>
|
||||
<div class="btn-wrapper q-ml-md row items-center">
|
||||
<q-btn
|
||||
color="primary"
|
||||
|
@ -27,19 +27,27 @@
|
|||
</div>
|
||||
<div v-if="session_records.length > 0" class="records-group">
|
||||
<span class="record-type-title">{{
|
||||
$t("titles.lnsSessionRecords")
|
||||
$t("titles.onsSessionRecords")
|
||||
}}</span>
|
||||
<LNSRecordList
|
||||
<ONSRecordList
|
||||
:record-list="session_records"
|
||||
:is-lokinet="false"
|
||||
@onUpdate="onUpdate"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="wallet_records.length > 0" class="records-group">
|
||||
<span class="record-type-title">{{ $t("titles.onsWalletRecords") }}</span>
|
||||
<ONSRecordList
|
||||
:record-list="wallet_records"
|
||||
:is-lokinet="false"
|
||||
@onUpdate="onUpdate"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="lokinet_records.length > 0" class="records-group">
|
||||
<span class="record-type-title">{{
|
||||
$t("titles.lnsLokinetRecords")
|
||||
$t("titles.onsLokinetRecords")
|
||||
}}</span>
|
||||
<LNSRecordList
|
||||
<ONSRecordList
|
||||
:record-list="lokinet_records"
|
||||
:is-lokinet="true"
|
||||
@onUpdate="onUpdate"
|
||||
|
@ -51,15 +59,15 @@
|
|||
|
||||
<script>
|
||||
import { mapState } from "vuex";
|
||||
import LokiField from "components/loki_field";
|
||||
import OxenField from "components/oxen_field";
|
||||
import { session_name_or_lokinet_name } from "src/validators/common";
|
||||
import LNSRecordList from "./lns_record_list";
|
||||
import ONSRecordList from "./ons_record_list";
|
||||
|
||||
export default {
|
||||
name: "LNSRecords",
|
||||
name: "ONSRecords",
|
||||
components: {
|
||||
LokiField,
|
||||
LNSRecordList
|
||||
OxenField,
|
||||
ONSRecordList
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -68,7 +76,7 @@ export default {
|
|||
};
|
||||
},
|
||||
mounted() {
|
||||
this.$gateway.send("wallet", "lns_known_names");
|
||||
this.$gateway.send("wallet", "ons_known_names");
|
||||
},
|
||||
computed: mapState({
|
||||
theme: state => state.gateway.app.config.appearance.theme,
|
||||
|
@ -81,11 +89,18 @@ export default {
|
|||
session_records(state) {
|
||||
return this.records_of_type(state, "session");
|
||||
},
|
||||
wallet_records(state) {
|
||||
return this.records_of_type(state, "wallet");
|
||||
},
|
||||
lokinet_records(state) {
|
||||
return this.records_of_type(state, "lokinet");
|
||||
},
|
||||
needsDecryption() {
|
||||
const records = [...this.lokinet_records, ...this.session_records];
|
||||
const records = [
|
||||
...this.lokinet_records,
|
||||
...this.session_records,
|
||||
...this.wallet_records
|
||||
];
|
||||
return records.find(r => this.isLocked(r));
|
||||
}
|
||||
}),
|
||||
|
@ -93,7 +108,7 @@ export default {
|
|||
records_of_type(state, type) {
|
||||
// receives the type and returns the records of that type
|
||||
const ourAddresses = this.ourAddresses;
|
||||
const records = state.gateway.wallet.lnsRecords;
|
||||
const records = state.gateway.wallet.onsRecords;
|
||||
const ourRecords = records.filter(record => {
|
||||
return (
|
||||
record.type === type &&
|
||||
|
@ -151,7 +166,7 @@ export default {
|
|||
this.$q.notify({
|
||||
type: "positive",
|
||||
timeout: 2000,
|
||||
message: this.$t("notification.positive.decryptedLNSRecord", {
|
||||
message: this.$t("notification.positive.decryptedONSRecord", {
|
||||
name
|
||||
})
|
||||
});
|
||||
|
@ -160,7 +175,7 @@ export default {
|
|||
this.$q.notify({
|
||||
type: "negative",
|
||||
timeout: 3000,
|
||||
message: this.$t("notification.errors.decryptLNSRecord", { name })
|
||||
message: this.$t("notification.errors.decryptONSRecord", { name })
|
||||
});
|
||||
}
|
||||
this.decrypting = false;
|
||||
|
@ -189,7 +204,7 @@ export default {
|
|||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.lns-record-list {
|
||||
.ons-record-list {
|
||||
.height {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
@ -197,7 +212,7 @@ export default {
|
|||
cursor: default;
|
||||
}
|
||||
|
||||
.loki-field {
|
||||
.oxen-field {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
|
@ -209,14 +224,4 @@ export default {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.record-type-title {
|
||||
font-weight: bold;
|
||||
margin-bottom: 40px;
|
||||
padding-bottom: 40px;
|
||||
}
|
||||
|
||||
.records-group {
|
||||
padding-bottom: 40px;
|
||||
}
|
||||
</style>
|
|
@ -1,8 +1,10 @@
|
|||
<template>
|
||||
<div class="loki-field" :class="{ disable, 'disable-hover': disableHover }">
|
||||
<div class="oxen-field" :class="{ disable, 'disable-hover': disableHover }">
|
||||
<div v-if="label" class="label row items-center" :disabled="disable">
|
||||
{{ label }}
|
||||
<span v-if="optional" class="optional">({{ $t("fieldLabels.optional") }})</span>
|
||||
<span v-if="optional" class="optional"
|
||||
>({{ $t("fieldLabels.optional") }})</span
|
||||
>
|
||||
</div>
|
||||
<div class="content row items-center" :class="{ error }">
|
||||
<slot></slot>
|
||||
|
@ -15,7 +17,7 @@
|
|||
|
||||
<script>
|
||||
export default {
|
||||
name: "LokiField",
|
||||
name: "OxenField",
|
||||
props: {
|
||||
label: {
|
||||
type: String,
|
||||
|
@ -55,7 +57,7 @@ export default {
|
|||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.loki-field {
|
||||
.oxen-field {
|
||||
.label {
|
||||
margin: 6px 0;
|
||||
font-weight: bold;
|
||||
|
@ -90,7 +92,14 @@ export default {
|
|||
margin: 0;
|
||||
|
||||
* {
|
||||
color: white;
|
||||
// Oxen navy, can't use vars here :(
|
||||
color: #1f1c47;
|
||||
}
|
||||
}
|
||||
|
||||
.q-select {
|
||||
.row {
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,20 +1,34 @@
|
|||
<template>
|
||||
<q-list class="loki-list-item" no-border @click.native="details(address)">
|
||||
<q-list class="oxen-list-item" no-border @click.native="details(address)">
|
||||
<q-item>
|
||||
<q-item-section class="flex">
|
||||
<q-item-label class="ellipsis">{{ address.address }}</q-item-label>
|
||||
<q-item-label v-if="sublabel" caption class="non-selectable">{{ sublabel }}</q-item-label>
|
||||
<q-item-label v-if="sublabel" caption class="non-selectable">{{
|
||||
sublabel
|
||||
}}</q-item-label>
|
||||
</q-item-section>
|
||||
<q-item-section side>
|
||||
<div class="row">
|
||||
<q-btn style="margin-right: 4px;" flat padding="xs" size="md" @click="showQR(address.address, $event)">
|
||||
<q-btn
|
||||
style="margin-right: 4px;"
|
||||
flat
|
||||
padding="xs"
|
||||
size="md"
|
||||
@click="showQR(address.address, $event)"
|
||||
>
|
||||
<!-- height of 24 makes it equal size as copy -->
|
||||
<img :src="qrImage" height="24" />
|
||||
<q-tooltip anchor="bottom right" self="top right" :offset="[0, 5]">
|
||||
{{ $t("menuItems.showQRCode") }}
|
||||
</q-tooltip>
|
||||
</q-btn>
|
||||
<q-btn flat padding="xs" size="md" icon="file_copy" @click="copyAddress(address.address, $event)">
|
||||
<q-btn
|
||||
flat
|
||||
padding="xs"
|
||||
size="md"
|
||||
icon="file_copy"
|
||||
@click="copyAddress(address.address, $event)"
|
||||
>
|
||||
<q-tooltip anchor="bottom right" self="top right" :offset="[0, 5]">
|
||||
{{ $t("menuItems.copyAddress") }}
|
||||
</q-tooltip>
|
||||
|
@ -28,19 +42,23 @@
|
|||
<q-item-section>
|
||||
<div class="row info-section">
|
||||
<span class="col-sm-4">
|
||||
<span>{{ $t("strings.lokiBalance") }}</span>
|
||||
<span>{{ $t("strings.oxenBalance") }}</span>
|
||||
<br />
|
||||
<span class="value">{{ address.balance | currency }}</span>
|
||||
</span>
|
||||
<span class="col-sm-4">
|
||||
<span>{{ $t("strings.lokiUnlockedBalance") }}</span>
|
||||
<span>{{ $t("strings.oxenUnlockedBalance") }}</span>
|
||||
<br />
|
||||
<span class="value">{{ address.unlocked_balance | currency }}</span>
|
||||
<span class="value">{{
|
||||
address.unlocked_balance | currency
|
||||
}}</span>
|
||||
</span>
|
||||
<span class="col-sm-4">
|
||||
<span>{{ $t("strings.unspentOutputs") }}</span>
|
||||
<br />
|
||||
<span class="value">{{ address.num_unspent_outputs | toString }}</span>
|
||||
<span class="value">{{
|
||||
address.num_unspent_outputs | toString
|
||||
}}</span>
|
||||
</span>
|
||||
</div>
|
||||
</q-item-section>
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
/>
|
||||
</q-toolbar>
|
||||
</q-header>
|
||||
<q-page-container>
|
||||
<q-page-container class="detail-page">
|
||||
<div class="layout-padding">
|
||||
<h6 class="q-mt-xs q-mb-none text-weight-light">
|
||||
{{ $t("strings.serviceNodeDetails.serviceNodeKey") }}
|
||||
|
@ -40,7 +40,7 @@
|
|||
</div>
|
||||
<div class="value">
|
||||
<span
|
||||
><FormatLoki :amount="node.staking_requirement" raw-value
|
||||
><FormatOxen :amount="node.staking_requirement" raw-value
|
||||
/></span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -54,7 +54,7 @@
|
|||
</div>
|
||||
<div class="value">
|
||||
<span
|
||||
><FormatLoki :amount="node.total_contributed" raw-value
|
||||
><FormatOxen :amount="node.total_contributed" raw-value
|
||||
/></span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -120,7 +120,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<q-list no-border :dark="theme == 'dark'" class="loki-list">
|
||||
<q-list no-border :dark="theme == 'dark'" class="oxen-list">
|
||||
<q-item-label class="contributors-title"
|
||||
>{{
|
||||
$t("strings.serviceNodeDetails.contributors")
|
||||
|
@ -129,7 +129,7 @@
|
|||
<q-item
|
||||
v-for="contributor in contributors"
|
||||
:key="contributor.address"
|
||||
class="loki-list-item"
|
||||
class="oxen-list-item"
|
||||
clickable
|
||||
@click="openUserWalletInfo(contributor.address)"
|
||||
>
|
||||
|
@ -150,7 +150,7 @@
|
|||
>{{ $t("strings.operator") }} •
|
||||
</span>
|
||||
{{ $t("strings.contribution") }}:
|
||||
<FormatLoki :amount="contributor.amount" raw-value />
|
||||
<FormatOxen :amount="contributor.amount" raw-value />
|
||||
</q-item-label>
|
||||
</q-item-label>
|
||||
<ContextMenu
|
||||
|
@ -175,12 +175,12 @@
|
|||
const { clipboard } = require("electron");
|
||||
import { mapState } from "vuex";
|
||||
import { date } from "quasar";
|
||||
import FormatLoki from "components/format_loki";
|
||||
import FormatOxen from "components/format_oxen";
|
||||
import ContextMenu from "components/menus/contextmenu";
|
||||
export default {
|
||||
name: "ServiceNodeDetails",
|
||||
components: {
|
||||
FormatLoki,
|
||||
FormatOxen,
|
||||
ContextMenu
|
||||
},
|
||||
props: {
|
||||
|
@ -245,7 +245,7 @@ export default {
|
|||
}),
|
||||
methods: {
|
||||
openUserWalletInfo(contributorAddress) {
|
||||
const url = `https://www.lokisn.com/user/${contributorAddress}`;
|
||||
const url = `https://www.oxensn.com/user/${contributorAddress}`;
|
||||
this.$gateway.send("core", "open_url", {
|
||||
url
|
||||
});
|
||||
|
@ -280,6 +280,7 @@ export default {
|
|||
<style lang="scss">
|
||||
.contributors-title {
|
||||
margin-bottom: 12px;
|
||||
color: #1f1c47;
|
||||
}
|
||||
|
||||
.serviceNodeDetails {
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
<span v-if="getRole(node)">{{ getRole(node) }} •</span>
|
||||
<span>
|
||||
{{ $t("strings.contribution") }}:
|
||||
<FormatLoki :amount="node.ourContributionAmount" />
|
||||
<FormatOxen :amount="node.ourContributionAmount" />
|
||||
</span>
|
||||
</span>
|
||||
<!-- you only have a contribution amount of 0 if you are a "contributor"
|
||||
|
@ -28,18 +28,16 @@
|
|||
>
|
||||
{{ $t("strings.serviceNodeDetails.reserved") }} •
|
||||
</span>
|
||||
<span v-if="node.awaitingContribution">
|
||||
<span v-if="node.awaitingContribution" class="contrib-amounts">
|
||||
{{ $t("strings.serviceNodeDetails.minContribution") }}:
|
||||
{{ getMinContribution(node) }} LOKI •
|
||||
{{ getMinContribution(node, our_address) }} OXEN •
|
||||
{{ $t("strings.serviceNodeDetails.maxContribution") }}:
|
||||
{{ openForContributionLoki(node) }} LOKI
|
||||
{{ openForContributionOxen(node, our_address) }} OXEN
|
||||
</span>
|
||||
</q-item-label>
|
||||
</q-item-section>
|
||||
<q-item-section side>
|
||||
<span style="font-size: 16px; color: #cecece">{{
|
||||
getFee(node)
|
||||
}}</span>
|
||||
<span class="fee">{{ getFee(node) }}</span>
|
||||
</q-item-section>
|
||||
<q-item-section side>
|
||||
<q-btn
|
||||
|
@ -72,7 +70,7 @@
|
|||
<script>
|
||||
import { clipboard } from "electron";
|
||||
import ContextMenu from "components/menus/contextmenu";
|
||||
import FormatLoki from "components/format_loki";
|
||||
import FormatOxen from "components/format_oxen";
|
||||
import ServiceNodeMixin from "src/mixins/service_node_mixin";
|
||||
import { mapState } from "vuex";
|
||||
|
||||
|
@ -80,7 +78,7 @@ export default {
|
|||
name: "ServiceNodeList",
|
||||
components: {
|
||||
ContextMenu,
|
||||
FormatLoki
|
||||
FormatOxen
|
||||
},
|
||||
mixins: [ServiceNodeMixin],
|
||||
props: {
|
||||
|
@ -120,7 +118,7 @@ export default {
|
|||
nodeWithMinContribution(node) {
|
||||
const nodeWithMinContribution = {
|
||||
...node,
|
||||
minContribution: this.getMinContribution(node)
|
||||
minContribution: this.getMinContribution(node, this.our_address)
|
||||
};
|
||||
return nodeWithMinContribution;
|
||||
},
|
||||
|
@ -168,4 +166,4 @@ export default {
|
|||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
<style lang="scss"></style>
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
<template>
|
||||
<div class="service-node-registration">
|
||||
<div class="q-pa-md">
|
||||
<i18n path="strings.serviceNodeRegistrationDescription" tag="div" class="description q-mb-lg">
|
||||
<i18n
|
||||
path="strings.serviceNodeRegistrationDescription"
|
||||
tag="div"
|
||||
class="tab-desc q-mb-lg"
|
||||
>
|
||||
<b place="registerCommand">register_service_node</b>
|
||||
<b place="prepareCommand">prepare_registration</b>
|
||||
</i18n>
|
||||
<LokiField
|
||||
<OxenField
|
||||
:label="$t('fieldLabels.serviceNodeCommand')"
|
||||
:error="$v.registration_string.$error"
|
||||
:disabled="registration_status.sending"
|
||||
|
@ -13,8 +17,7 @@
|
|||
<q-input
|
||||
v-model.trim="registration_string"
|
||||
type="textarea"
|
||||
:dark="theme == 'dark'"
|
||||
class="full-width text-area-loki"
|
||||
class="full-width text-area-oxen"
|
||||
placeholder="register_service_node ..."
|
||||
:disabled="registration_status.sending"
|
||||
borderless
|
||||
|
@ -22,7 +25,7 @@
|
|||
@blur="$v.registration_string.$touch"
|
||||
@paste="onPaste"
|
||||
/>
|
||||
</LokiField>
|
||||
</OxenField>
|
||||
<q-btn
|
||||
class="register-button"
|
||||
color="primary"
|
||||
|
@ -32,7 +35,7 @@
|
|||
/>
|
||||
</div>
|
||||
|
||||
<q-inner-loading :showing="registration_status.sending" :dark="theme == 'dark'">
|
||||
<q-inner-loading :showing="registration_status.sending">
|
||||
<q-spinner color="primary" size="30" />
|
||||
</q-inner-loading>
|
||||
</div>
|
||||
|
@ -41,13 +44,13 @@
|
|||
<script>
|
||||
import { mapState } from "vuex";
|
||||
import { required } from "vuelidate/lib/validators";
|
||||
import LokiField from "components/loki_field";
|
||||
import OxenField from "components/oxen_field";
|
||||
import WalletPassword from "src/mixins/wallet_password";
|
||||
|
||||
export default {
|
||||
name: "ServiceNodeRegistration",
|
||||
components: {
|
||||
LokiField
|
||||
OxenField
|
||||
},
|
||||
mixins: [WalletPassword],
|
||||
data() {
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
<template>
|
||||
<div class="service-node-staking">
|
||||
<div class="q-px-md q-pt-md">
|
||||
<p style="color: #cecece">
|
||||
<p class="tab-desc">
|
||||
{{ $t("strings.serviceNodeContributionDescription") }}
|
||||
<span
|
||||
style="cursor: pointer; text-decoration: underline;"
|
||||
@click="lokiWebsite"
|
||||
>Loki {{ $t("strings.website") }}.</span
|
||||
@click="oxenWebsite"
|
||||
>Oxen {{ $t("strings.website") }}.</span
|
||||
>
|
||||
</p>
|
||||
<LokiField
|
||||
<OxenField
|
||||
:label="$t('fieldLabels.serviceNodeKey')"
|
||||
:error="$v.service_node.key.$error"
|
||||
>
|
||||
|
@ -21,8 +21,8 @@
|
|||
dense
|
||||
@blur="$v.service_node.key.$touch"
|
||||
/>
|
||||
</LokiField>
|
||||
<LokiField
|
||||
</OxenField>
|
||||
<OxenField
|
||||
:label="$t('fieldLabels.amount')"
|
||||
class="q-mt-md"
|
||||
:error="$v.service_node.amount.$error"
|
||||
|
@ -39,20 +39,20 @@
|
|||
@blur="$v.service_node.amount.$touch"
|
||||
/>
|
||||
<q-btn
|
||||
color="secondary"
|
||||
color="primary"
|
||||
:text-color="theme == 'dark' ? 'white' : 'dark'"
|
||||
:label="$t('buttons.min')"
|
||||
:disable="!areButtonsEnabled()"
|
||||
@click="service_node.amount = minStake(service_node.key)"
|
||||
/>
|
||||
<q-btn
|
||||
color="secondary"
|
||||
color="primary"
|
||||
:text-color="theme == 'dark' ? 'white' : 'dark'"
|
||||
:label="$t('buttons.max')"
|
||||
:disable="!areButtonsEnabled()"
|
||||
@click="service_node.amount = maxStake(service_node.key)"
|
||||
/>
|
||||
</LokiField>
|
||||
</OxenField>
|
||||
<div class="submit-button">
|
||||
<q-btn
|
||||
:disable="!is_able_to_send"
|
||||
|
@ -62,7 +62,7 @@
|
|||
/>
|
||||
<q-btn
|
||||
:disable="!is_able_to_send"
|
||||
color="secondary"
|
||||
color="accent"
|
||||
:label="$t('buttons.sweepAll')"
|
||||
@click="sweepAllWarning()"
|
||||
/>
|
||||
|
@ -84,7 +84,6 @@
|
|||
/>
|
||||
<q-inner-loading
|
||||
:showing="stake_status.sending || sweep_all_status.sending"
|
||||
:dark="theme == 'dark'"
|
||||
>
|
||||
<q-spinner color="primary" size="30" />
|
||||
</q-inner-loading>
|
||||
|
@ -96,7 +95,7 @@ const objectAssignDeep = require("object-assign-deep");
|
|||
import { mapState } from "vuex";
|
||||
import { required, decimal } from "vuelidate/lib/validators";
|
||||
import { service_node_key, greater_than_zero } from "src/validators/common";
|
||||
import LokiField from "components/loki_field";
|
||||
import OxenField from "components/oxen_field";
|
||||
import WalletPassword from "src/mixins/wallet_password";
|
||||
import ConfirmDialogMixin from "src/mixins/confirm_dialog_mixin";
|
||||
import ServiceNodeContribute from "./service_node_contribute";
|
||||
|
@ -108,7 +107,7 @@ const DO_NOTHING = 10;
|
|||
export default {
|
||||
name: "ServiceNodeStaking",
|
||||
components: {
|
||||
LokiField,
|
||||
OxenField,
|
||||
ServiceNodeContribute,
|
||||
ConfirmTransactionDialog
|
||||
},
|
||||
|
@ -152,17 +151,24 @@ export default {
|
|||
},
|
||||
awaiting_service_nodes(state) {
|
||||
const nodes = state.gateway.daemon.service_nodes.nodes;
|
||||
// a reserved node is one on which someone is a "contributor" of amount = 0
|
||||
const getOurContribution = node =>
|
||||
node.contributors.find(
|
||||
c => c.address === this.our_address && c.amount > 0
|
||||
c => c.address === this.award_address && c.amount > 0
|
||||
);
|
||||
// a reserved node is one on which someone is a "contributor" of amount = 0
|
||||
const reservedForUs = node =>
|
||||
node.contributors.find(
|
||||
c => c.address === this.award_address && c.amount == 0
|
||||
);
|
||||
const isAwaitingContribution = node =>
|
||||
!node.active && !node.funded && node.requested_unlock_height === 0;
|
||||
!node.active && !node.funded;
|
||||
const isAwaitingContributionNonReserved = node =>
|
||||
isAwaitingContribution(node) && !getOurContribution(node);
|
||||
node.requested_unlock_height === 0 &&
|
||||
isAwaitingContribution(node) &&
|
||||
!getOurContribution(node) &&
|
||||
this.openForContribution(node) > 0;
|
||||
const isAwaitingContributionReserved = node =>
|
||||
isAwaitingContribution(node) && getOurContribution(node);
|
||||
isAwaitingContribution(node) && reservedForUs(node);
|
||||
|
||||
// we want the reserved nodes sorted by fee at the top
|
||||
const awaitingContributionNodesReserved = nodes
|
||||
|
@ -278,8 +284,8 @@ export default {
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
lokiWebsite() {
|
||||
const url = "https://loki.network/service-nodes/";
|
||||
oxenWebsite() {
|
||||
const url = "https://oxen.io/";
|
||||
this.$gateway.send("core", "open_url", {
|
||||
url
|
||||
});
|
||||
|
@ -290,11 +296,11 @@ export default {
|
|||
},
|
||||
minStake() {
|
||||
const node = this.getNodeWithPubKey();
|
||||
return this.getMinContribution(node);
|
||||
return this.getMinContribution(node, this.award_address);
|
||||
},
|
||||
maxStake() {
|
||||
const node = this.getNodeWithPubKey();
|
||||
return this.openForContributionLoki(node);
|
||||
return this.openForContributionOxen(node, this.award_address);
|
||||
},
|
||||
getFeeDecimal(node) {
|
||||
const operatorPortion = node.portions_for_operator;
|
||||
|
@ -353,9 +359,8 @@ export default {
|
|||
cancel: {
|
||||
flat: true,
|
||||
label: this.$t("dialog.buttons.cancel"),
|
||||
color: this.theme === "dark" ? "white" : "dark"
|
||||
},
|
||||
dark: this.theme === "dark"
|
||||
color: "negative"
|
||||
}
|
||||
})
|
||||
.onOk(() => {
|
||||
this.sweepAll();
|
||||
|
@ -387,10 +392,8 @@ export default {
|
|||
noPasswordMessage: this.$t("dialog.sweepAll.message"),
|
||||
ok: {
|
||||
label: this.$t("dialog.sweepAll.ok"),
|
||||
color: "primary"
|
||||
},
|
||||
dark: this.theme == "dark",
|
||||
color: this.theme == "dark" ? "white" : "dark"
|
||||
color: "#12C7BA"
|
||||
}
|
||||
});
|
||||
passwordDialog
|
||||
.onOk(password => {
|
||||
|
|
|
@ -72,13 +72,20 @@ export default {
|
|||
node.contributors.find(
|
||||
c => c.address === this.our_address && c.amount > 0
|
||||
);
|
||||
return nodes.filter(getOurContribution).map(n => {
|
||||
const ourContribution = getOurContribution(n);
|
||||
return {
|
||||
...n,
|
||||
ourContributionAmount: ourContribution.amount
|
||||
};
|
||||
});
|
||||
return nodes
|
||||
.filter(getOurContribution)
|
||||
.sort((a, b) => {
|
||||
if (a.service_node_pubkey < b.service_node_pubkey) return -1;
|
||||
if (a.service_node_pubkey > b.service_node_pubkey) return 1;
|
||||
return 0;
|
||||
})
|
||||
.map(n => {
|
||||
const ourContribution = getOurContribution(n);
|
||||
return {
|
||||
...n,
|
||||
ourContributionAmount: ourContribution.amount
|
||||
};
|
||||
});
|
||||
},
|
||||
fetching: state => state.gateway.daemon.service_nodes.fetching
|
||||
}),
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<q-btn-toggle
|
||||
v-model="page"
|
||||
toggle-color="primary"
|
||||
color="tertiary"
|
||||
color="accent"
|
||||
size="md"
|
||||
:options="tabs"
|
||||
/>
|
||||
|
@ -29,7 +29,7 @@
|
|||
</div>
|
||||
|
||||
<div v-if="page == 'peers'">
|
||||
<q-list :dark="theme == 'dark'" no-border>
|
||||
<q-list no-border>
|
||||
<q-item-label header>{{ $t("strings.peerList") }}</q-item-label>
|
||||
<q-item
|
||||
v-for="entry in daemon.connections"
|
||||
|
|
|
@ -24,19 +24,19 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<p v-if="config_daemon.type == 'local_remote'">
|
||||
<p v-if="config_daemon.type == 'local_remote'" class="tab-desc">
|
||||
{{ $t("strings.daemon.localRemote.description") }}
|
||||
</p>
|
||||
<p v-if="config_daemon.type == 'local'">
|
||||
<p v-if="config_daemon.type == 'local'" class="tab-desc">
|
||||
{{ $t("strings.daemon.local.description") }}
|
||||
</p>
|
||||
<p v-if="is_remote">
|
||||
<p v-if="is_remote" class="tab-desc">
|
||||
{{ $t("strings.daemon.remote.description") }}
|
||||
</p>
|
||||
|
||||
<template v-if="config_daemon.type != 'remote'">
|
||||
<div class="row pl-sm">
|
||||
<LokiField
|
||||
<OxenField
|
||||
class="col-8"
|
||||
:label="$t('fieldLabels.localDaemonIP')"
|
||||
disable
|
||||
|
@ -44,13 +44,12 @@
|
|||
<q-input
|
||||
v-model="config_daemon.rpc_bind_ip"
|
||||
:placeholder="daemon_defaults.rpc_bind_ip"
|
||||
:dark="theme == 'dark'"
|
||||
disable
|
||||
borderless
|
||||
dense
|
||||
/>
|
||||
</LokiField>
|
||||
<LokiField
|
||||
</OxenField>
|
||||
<OxenField
|
||||
class="col-4"
|
||||
:label="$t('fieldLabels.localDaemonPort') + '(RPC)'"
|
||||
>
|
||||
|
@ -62,21 +61,19 @@
|
|||
:step="1"
|
||||
min="1024"
|
||||
max="65535"
|
||||
:dark="theme == 'dark'"
|
||||
borderless
|
||||
dense
|
||||
/>
|
||||
</LokiField>
|
||||
</OxenField>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-if="config_daemon.type != 'local'">
|
||||
<div class="row q-mt-md pl-sm">
|
||||
<LokiField class="col-8" :label="$t('fieldLabels.remoteNodeHost')">
|
||||
<OxenField class="col-8" :label="$t('fieldLabels.remoteNodeHost')">
|
||||
<q-input
|
||||
v-model="config_daemon.remote_host"
|
||||
:placeholder="daemon_defaults.remote_host"
|
||||
:dark="theme == 'dark'"
|
||||
borderless
|
||||
dense
|
||||
/>
|
||||
|
@ -86,7 +83,7 @@
|
|||
class="remote-dropdown"
|
||||
flat
|
||||
>
|
||||
<q-list link dark no-border>
|
||||
<q-list link no-border>
|
||||
<q-item
|
||||
v-for="option in remotes"
|
||||
:key="option.host"
|
||||
|
@ -101,8 +98,8 @@
|
|||
</q-item>
|
||||
</q-list>
|
||||
</q-btn-dropdown>
|
||||
</LokiField>
|
||||
<LokiField class="col-4" :label="$t('fieldLabels.remoteNodePort')">
|
||||
</OxenField>
|
||||
<OxenField class="col-4" :label="$t('fieldLabels.remoteNodePort')">
|
||||
<q-input
|
||||
v-model="config_daemon.remote_port"
|
||||
:placeholder="toString(daemon_defaults.remote_port)"
|
||||
|
@ -115,12 +112,12 @@
|
|||
borderless
|
||||
dense
|
||||
/>
|
||||
</LokiField>
|
||||
</OxenField>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="col q-mt-md pt-sm">
|
||||
<LokiField :label="$t('fieldLabels.dataStoragePath')" disable-hover>
|
||||
<OxenField :label="$t('fieldLabels.dataStoragePath')" disable-hover>
|
||||
<q-input
|
||||
v-model="config.app.data_dir"
|
||||
disable
|
||||
|
@ -138,13 +135,13 @@
|
|||
@change="setDataPath"
|
||||
/>
|
||||
<q-btn
|
||||
color="secondary"
|
||||
color="primary"
|
||||
:text-color="theme == 'dark' ? 'white' : 'dark'"
|
||||
@click="selectPath('data')"
|
||||
>{{ $t("buttons.selectLocation") }}</q-btn
|
||||
>
|
||||
</LokiField>
|
||||
<LokiField :label="$t('fieldLabels.walletStoragePath')" disable-hover>
|
||||
</OxenField>
|
||||
<OxenField :label="$t('fieldLabels.walletStoragePath')" disable-hover>
|
||||
<q-input
|
||||
v-model="config.app.wallet_data_dir"
|
||||
disable
|
||||
|
@ -162,12 +159,12 @@
|
|||
@change="setWalletDataPath"
|
||||
/>
|
||||
<q-btn
|
||||
color="secondary"
|
||||
color="primary"
|
||||
:text-color="theme == 'dark' ? 'white' : 'dark'"
|
||||
@click="selectPath('wallet')"
|
||||
>{{ $t("buttons.selectLocation") }}</q-btn
|
||||
>
|
||||
</LokiField>
|
||||
</OxenField>
|
||||
</div>
|
||||
|
||||
<q-expansion-item
|
||||
|
@ -175,7 +172,7 @@
|
|||
header-class="q-mt-sm non-selectable row reverse advanced-options-label"
|
||||
>
|
||||
<div class="row pl-sm q-mt-sm">
|
||||
<LokiField
|
||||
<OxenField
|
||||
class="col-6"
|
||||
:label="$t('fieldLabels.daemonLogLevel')"
|
||||
:disable="is_remote"
|
||||
|
@ -193,8 +190,8 @@
|
|||
borderless
|
||||
dense
|
||||
/>
|
||||
</LokiField>
|
||||
<LokiField class="col-6" :label="$t('fieldLabels.walletLogLevel')">
|
||||
</OxenField>
|
||||
<OxenField class="col-6" :label="$t('fieldLabels.walletLogLevel')">
|
||||
<q-input
|
||||
v-model="config.wallet.log_level"
|
||||
:placeholder="toString(defaults.wallet.log_level)"
|
||||
|
@ -207,12 +204,12 @@
|
|||
borderless
|
||||
dense
|
||||
/>
|
||||
</LokiField>
|
||||
</OxenField>
|
||||
</div>
|
||||
|
||||
<div class="row pl-sm q-mt-md">
|
||||
<!-- TODO: Can be generalised to a "port" (or similar) field -->
|
||||
<LokiField
|
||||
<OxenField
|
||||
class="col-3"
|
||||
:label="$t('fieldLabels.maxIncomingPeers')"
|
||||
:disable="is_remote"
|
||||
|
@ -230,8 +227,8 @@
|
|||
borderless
|
||||
dense
|
||||
/>
|
||||
</LokiField>
|
||||
<LokiField
|
||||
</OxenField>
|
||||
<OxenField
|
||||
class="col-3"
|
||||
:label="$t('fieldLabels.maxOutgoingPeers')"
|
||||
:disable="is_remote"
|
||||
|
@ -249,8 +246,8 @@
|
|||
borderless
|
||||
dense
|
||||
/>
|
||||
</LokiField>
|
||||
<LokiField
|
||||
</OxenField>
|
||||
<OxenField
|
||||
class="col-3"
|
||||
:label="$t('fieldLabels.limitUploadRate')"
|
||||
:disable="is_remote"
|
||||
|
@ -269,8 +266,8 @@
|
|||
borderless
|
||||
dense
|
||||
/>
|
||||
</LokiField>
|
||||
<LokiField
|
||||
</OxenField>
|
||||
<OxenField
|
||||
class="col-3"
|
||||
:label="$t('fieldLabels.limitDownloadRate')"
|
||||
:disable="is_remote"
|
||||
|
@ -289,10 +286,10 @@
|
|||
borderless
|
||||
dense
|
||||
/>
|
||||
</LokiField>
|
||||
</OxenField>
|
||||
</div>
|
||||
<div class="row pl-sm q-mt-md">
|
||||
<LokiField
|
||||
<OxenField
|
||||
class="col-3"
|
||||
:label="$t('fieldLabels.daemonP2pPort')"
|
||||
:disable="is_remote"
|
||||
|
@ -311,8 +308,8 @@
|
|||
borderless
|
||||
dense
|
||||
/>
|
||||
</LokiField>
|
||||
<LokiField class="col-3" :label="$t('fieldLabels.internalWalletPort')">
|
||||
</OxenField>
|
||||
<OxenField class="col-3" :label="$t('fieldLabels.internalWalletPort')">
|
||||
<q-input
|
||||
v-model="config.app.ws_bind_port"
|
||||
:placeholder="toString(defaults.app.ws_bind_port)"
|
||||
|
@ -326,8 +323,8 @@
|
|||
borderless
|
||||
dense
|
||||
/>
|
||||
</LokiField>
|
||||
<LokiField
|
||||
</OxenField>
|
||||
<OxenField
|
||||
class="col-3"
|
||||
:label="$t('fieldLabels.walletRPCPort')"
|
||||
:disable="is_remote"
|
||||
|
@ -346,9 +343,9 @@
|
|||
borderless
|
||||
dense
|
||||
/>
|
||||
</LokiField>
|
||||
</OxenField>
|
||||
</div>
|
||||
<LokiField
|
||||
<OxenField
|
||||
:helper="$t('fieldLabels.chooseNetwork')"
|
||||
:label="$t('fieldLabels.network')"
|
||||
class="network-group-field"
|
||||
|
@ -362,18 +359,18 @@
|
|||
{ label: 'Test Net', value: 'testnet' }
|
||||
]"
|
||||
/>
|
||||
</LokiField>
|
||||
</OxenField>
|
||||
</q-expansion-item>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from "vuex";
|
||||
import LokiField from "components/loki_field";
|
||||
import OxenField from "components/oxen_field";
|
||||
export default {
|
||||
name: "SettingsGeneral",
|
||||
components: {
|
||||
LokiField
|
||||
OxenField
|
||||
},
|
||||
props: {
|
||||
randomiseRemote: {
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
/>
|
||||
</q-toolbar>
|
||||
</q-header>
|
||||
<q-page-container>
|
||||
<q-page-container class="detail-page">
|
||||
<div class="layout-padding">
|
||||
<div class="row items-center non-selectable">
|
||||
<div class="q-mr-sm">
|
||||
|
@ -72,7 +72,7 @@
|
|||
<span>{{ $t("strings.transactions.amount") }}</span>
|
||||
</div>
|
||||
<div class="value">
|
||||
<span><FormatLoki :amount="tx.amount" raw-value/></span>
|
||||
<span><FormatOxen :amount="tx.amount" raw-value/></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -88,7 +88,7 @@
|
|||
</span>
|
||||
</div>
|
||||
<div class="value">
|
||||
<span><FormatLoki :amount="tx.fee" raw-value/></span>
|
||||
<span><FormatOxen :amount="tx.fee" raw-value/></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -176,7 +176,7 @@
|
|||
destination.address
|
||||
}}</q-item-label>
|
||||
<q-item-label
|
||||
><FormatLoki :amount="destination.amount"
|
||||
><FormatOxen :amount="destination.amount"
|
||||
/></q-item-label>
|
||||
</q-item-label>
|
||||
<ContextMenu
|
||||
|
@ -200,8 +200,6 @@
|
|||
<q-input
|
||||
v-model="txNotes"
|
||||
:label="$t('fieldLabels.transactionNotes')"
|
||||
:dark="theme == 'dark'"
|
||||
:text-color="theme == 'dark' ? 'white' : 'dark'"
|
||||
type="textarea"
|
||||
rows="2"
|
||||
dense
|
||||
|
@ -225,13 +223,13 @@ const { clipboard } = require("electron");
|
|||
import { mapState } from "vuex";
|
||||
import { date } from "quasar";
|
||||
import TxTypeIcon from "components/tx_type_icon";
|
||||
import FormatLoki from "components/format_loki";
|
||||
import FormatOxen from "components/format_oxen";
|
||||
import ContextMenu from "components/menus/contextmenu";
|
||||
export default {
|
||||
name: "TxDetails",
|
||||
components: {
|
||||
TxTypeIcon,
|
||||
FormatLoki,
|
||||
FormatOxen,
|
||||
ContextMenu
|
||||
},
|
||||
data() {
|
||||
|
@ -327,8 +325,8 @@ export default {
|
|||
label: this.$t("dialog.transactionDetails.ok"),
|
||||
color: "primary"
|
||||
},
|
||||
dark: this.theme == "dark",
|
||||
style: "min-width: 500px; overflow-wrap: break-word;"
|
||||
style: "min-width: 500px; overflow-wrap: break-word;",
|
||||
color: "#1F1C47"
|
||||
})
|
||||
.onOk(() => {})
|
||||
.onCancel(() => {})
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div class="tx-list">
|
||||
<template v-if="tx_list_paged.length === 0">
|
||||
<p class="q-pa-md q-mb-none">
|
||||
<p class="q-pa-md q-mb-none tab-desc">
|
||||
{{ $t("strings.noTransactionsFound") }}
|
||||
</p>
|
||||
</template>
|
||||
|
@ -12,12 +12,12 @@
|
|||
link
|
||||
no-border
|
||||
:dark="theme == 'dark'"
|
||||
class="loki-list tx-list"
|
||||
class="oxen-list tx-list"
|
||||
>
|
||||
<q-item
|
||||
v-for="(tx, i) in tx_list_paged"
|
||||
:key="`${tx.txid}-${tx.type}-${i}`"
|
||||
class="loki-list-item transaction"
|
||||
class="oxen-list-item transaction"
|
||||
:class="'tx-' + tx.type"
|
||||
@click.native="details(tx)"
|
||||
>
|
||||
|
@ -26,7 +26,7 @@
|
|||
</q-item-section>
|
||||
<q-item-label class="main">
|
||||
<q-item-label class="amount">
|
||||
<FormatLoki :amount="tx.amount || 0" />
|
||||
<FormatOxen :amount="tx.amount || 0" />
|
||||
</q-item-label>
|
||||
<q-item-label caption>{{ tx.txid }}</q-item-label>
|
||||
</q-item-label>
|
||||
|
@ -61,7 +61,7 @@ const { clipboard } = require("electron");
|
|||
import { mapState } from "vuex";
|
||||
import { QSpinnerDots } from "quasar";
|
||||
import TxDetails from "components/tx_details";
|
||||
import FormatLoki from "components/format_loki";
|
||||
import FormatOxen from "components/format_oxen";
|
||||
import { i18n } from "boot/i18n";
|
||||
import ContextMenu from "components/menus/contextmenu";
|
||||
|
||||
|
@ -95,7 +95,7 @@ export default {
|
|||
components: {
|
||||
QSpinnerDots,
|
||||
TxDetails,
|
||||
FormatLoki,
|
||||
FormatOxen,
|
||||
ContextMenu
|
||||
},
|
||||
props: {
|
||||
|
@ -328,7 +328,7 @@ export default {
|
|||
|
||||
<style lang="scss">
|
||||
.tx-list {
|
||||
.loki-list-item {
|
||||
.oxen-list-item {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
|
|
@ -1,22 +1,52 @@
|
|||
<template>
|
||||
<div class="column wallet-info">
|
||||
<div class="row justify-between items-center wallet-header loki-green">
|
||||
<div class="row justify-between items-center wallet-header">
|
||||
<div class="title">{{ info.name }}</div>
|
||||
<WalletSettings />
|
||||
</div>
|
||||
<div class="wallet-content">
|
||||
<div class="wallet-content oxen-navy">
|
||||
<div class="row justify-center">
|
||||
<div class="funds column items-center">
|
||||
<div class="balance">
|
||||
<div class="text">
|
||||
<span>{{ $t("strings.lokiBalance") }}</span>
|
||||
</div>
|
||||
<q-btn-toggle
|
||||
v-model="balancestakeselector"
|
||||
text-color="white"
|
||||
toggle-text-color="primary"
|
||||
flat
|
||||
:options="[
|
||||
{
|
||||
label: $t('strings.oxenBalance'),
|
||||
value: 'balance'
|
||||
},
|
||||
{
|
||||
label: $t('strings.stake'),
|
||||
value: 'stake'
|
||||
}
|
||||
]"
|
||||
/>
|
||||
<div class="value">
|
||||
<span><FormatLoki :amount="info.balance"/></span>
|
||||
<span><FormatOxen :amount="info.balance"/></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row unlocked">
|
||||
<span>{{ $t("strings.lokiUnlockedShort") }}: <FormatLoki :amount="info.unlocked_balance"/></span>
|
||||
<div v-if="balancestakeselector != 'stake'" class="row unlocked">
|
||||
<span
|
||||
>{{ $t("strings.oxenUnlockedShort") }}:
|
||||
<FormatOxen :amount="info.unlocked_balance"
|
||||
/></span>
|
||||
</div>
|
||||
<div v-if="balancestakeselector == 'stake'" class="row unlocked">
|
||||
<span v-if="info.accrued_balance > 0"
|
||||
>{{ $t("strings.oxenAccumulatedRewards") }}:
|
||||
<FormatOxen :amount="info.accrued_balance" />•
|
||||
{{ $t("strings.nextPayout") }}:
|
||||
<FormatNextPayout
|
||||
:payout-block="info.accrued_balance_next_payout"
|
||||
:current-block="info.height"
|
||||
/>
|
||||
</span>
|
||||
<span v-if="info.accrued_balance == 0">
|
||||
No accumulated rewards from staking
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -30,20 +60,27 @@
|
|||
|
||||
<script>
|
||||
import { mapState } from "vuex";
|
||||
import FormatLoki from "components/format_loki";
|
||||
import FormatOxen from "components/format_oxen";
|
||||
import FormatNextPayout from "components/format_next_payout";
|
||||
import WalletSettings from "components/menus/wallet_settings";
|
||||
import CopyIcon from "components/icons/copy_icon";
|
||||
export default {
|
||||
name: "WalletDetails",
|
||||
components: {
|
||||
FormatLoki,
|
||||
FormatOxen,
|
||||
FormatNextPayout,
|
||||
WalletSettings,
|
||||
CopyIcon
|
||||
},
|
||||
computed: mapState({
|
||||
theme: state => state.gateway.app.config.appearance.theme,
|
||||
info: state => state.gateway.wallet.info
|
||||
})
|
||||
}),
|
||||
data() {
|
||||
return {
|
||||
balancestakeselector: "balance"
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
|
@ -58,7 +95,6 @@ export default {
|
|||
|
||||
.wallet-content {
|
||||
text-align: center;
|
||||
background-color: #0a0a0a;
|
||||
padding: 2em;
|
||||
|
||||
.balance {
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
<template>
|
||||
<q-item @click.native="openWallet(wallet)">
|
||||
<q-item-section avatar>
|
||||
<q-icon class="wallet-icon">
|
||||
<svg
|
||||
width="48"
|
||||
viewBox="0 0 17 16"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
class="si-glyph si-glyph-wallet"
|
||||
>
|
||||
<defs class="si-glyph-fill"></defs>
|
||||
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g transform="translate(1.000000, 0.000000)" fill="#434343">
|
||||
<path
|
||||
d="M7.988,10.635 L7.988,8.327 C7.988,7.578 8.561,6.969 9.267,6.969 L13.964,6.969 L13.964,5.531 C13.964,4.849 13.56,4.279 13.007,4.093 L13.007,4.094 L11.356,4.08 L11.336,4.022 L3.925,4.022 L3.784,4.07 L1.17,4.068 L1.165,4.047 C0.529,4.167 0.017,4.743 0.017,5.484 L0.017,13.437 C0.017,14.269 0.665,14.992 1.408,14.992 L12.622,14.992 C13.365,14.992 13.965,14.316 13.965,13.484 L13.965,12.031 L9.268,12.031 C8.562,12.031 7.988,11.384 7.988,10.635 L7.988,10.635 Z"
|
||||
class="si-glyph-fill"
|
||||
></path>
|
||||
<path
|
||||
d="M14.996,8.061 L14.947,8.061 L9.989,8.061 C9.46,8.061 9.031,8.529 9.031,9.106 L9.031,9.922 C9.031,10.498 9.46,10.966 9.989,10.966 L14.947,10.966 L14.996,10.966 C15.525,10.966 15.955,10.498 15.955,9.922 L15.955,9.106 C15.955,8.528 15.525,8.061 14.996,8.061 L14.996,8.061 Z M12.031,10.016 L9.969,10.016 L9.969,9 L12.031,9 L12.031,10.016 L12.031,10.016 Z"
|
||||
class="si-glyph-fill"
|
||||
></path>
|
||||
<path
|
||||
d="M3.926,4.022 L10.557,1.753 L11.337,4.022 L12.622,4.022 C12.757,4.022 12.885,4.051 13.008,4.092 L11.619,0.051 L1.049,3.572 L1.166,4.048 C1.245,4.033 1.326,4.023 1.408,4.023 L3.926,4.023 L3.926,4.022 Z"
|
||||
class="si-glyph-fill"
|
||||
></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</q-icon>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-item-label class="wallet-name" caption>{{ wallet.name }}</q-item-label>
|
||||
<q-item-label class="monospace ellipsis" caption>{{
|
||||
wallet.address
|
||||
}}</q-item-label>
|
||||
</q-item-section>
|
||||
<ContextMenu
|
||||
:menu-items="menuItems"
|
||||
@openWallet="openWallet(wallet)"
|
||||
@copyAddress="copyAddress(wallet.address)"
|
||||
/>
|
||||
</q-item>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const { clipboard } = require("electron");
|
||||
import { mapState } from "vuex";
|
||||
export default {
|
||||
name: "WalletListItem",
|
||||
props: {
|
||||
wallet: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
openWallet: {
|
||||
type: Function,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
computed: mapState({
|
||||
theme: state => state.gateway.app.config.appearance.theme,
|
||||
info: state => state.gateway.wallet.info
|
||||
}),
|
||||
methods: {
|
||||
copyAddress() {
|
||||
event.stopPropagation();
|
||||
for (let i = 0; i < event.path.length; i++) {
|
||||
if (event.path[i].tagName == "BUTTON") {
|
||||
event.path[i].blur();
|
||||
break;
|
||||
}
|
||||
}
|
||||
clipboard.writeText(this.wallet.address);
|
||||
this.$q.notify({
|
||||
type: "positive",
|
||||
timeout: 1000,
|
||||
message: this.$t("notification.positive.addressCopied")
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss"></style>
|
348
src/css/app.styl
|
@ -55,6 +55,7 @@ footer,
|
|||
font-family: 'RobotoMono-Light', monospace
|
||||
}
|
||||
|
||||
|
||||
.break-all {
|
||||
word-break: break-all
|
||||
}
|
||||
|
@ -72,7 +73,7 @@ footer,
|
|||
}
|
||||
}
|
||||
|
||||
.text-area-loki {
|
||||
.text-area-oxen {
|
||||
margin-top: 0px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
@ -100,8 +101,8 @@ footer,
|
|||
}
|
||||
|
||||
.q-layout, .app-content {
|
||||
background: $loki-black-80;
|
||||
color:white;
|
||||
background: white;
|
||||
color:$oxen-navy;
|
||||
}
|
||||
|
||||
.q-header {
|
||||
|
@ -138,7 +139,7 @@ footer,
|
|||
}
|
||||
|
||||
.q-toolbar-inverted {
|
||||
background: none;
|
||||
background: $oxen-navy;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
|
@ -153,9 +154,9 @@ footer,
|
|||
.q-tab {
|
||||
text-transform: none;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(12,12,12,0.15)
|
||||
}
|
||||
// &:hover {
|
||||
// background-color: rgba(12,12,12,0.15)
|
||||
// }
|
||||
|
||||
.q-icon {
|
||||
font-size: 22px;
|
||||
|
@ -196,19 +197,22 @@ footer,
|
|||
.text {
|
||||
font-size: 14px;
|
||||
margin-top: 8px;
|
||||
color: #cecece;
|
||||
color: $oxen-navy;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-size: 24px;
|
||||
margin-top: 4px;
|
||||
font-weight: 800;
|
||||
color: #cecece;
|
||||
font-weight:300;
|
||||
font-weight: 300;
|
||||
color: $oxen-navy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.q-checkbox {
|
||||
color: $oxen-navy
|
||||
}
|
||||
|
||||
.q-loading + .modal {
|
||||
z-index: 9999 !important;
|
||||
}
|
||||
|
@ -220,7 +224,7 @@ footer,
|
|||
}
|
||||
|
||||
.q-footer.status-footer {
|
||||
background: #000000;
|
||||
background: $oxen-navy;
|
||||
color: rgba(255, 255, 255, 0.51);
|
||||
border-top: 1px solid #333;
|
||||
padding-top: 2px;
|
||||
|
@ -242,7 +246,7 @@ footer,
|
|||
}
|
||||
|
||||
.ready {
|
||||
color: $loki-green-solid;
|
||||
color: $positive;
|
||||
}
|
||||
|
||||
.scanning, .syncing {
|
||||
|
@ -271,11 +275,12 @@ footer,
|
|||
}
|
||||
|
||||
div:first-child {
|
||||
background-color: $loki-green-dark-solid;
|
||||
// TODO: should first and last child be different, where even is this?
|
||||
background-color: $positive;
|
||||
}
|
||||
|
||||
div:last-child {
|
||||
background-color: $loki-green-solid;
|
||||
background-color: $positive;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -315,10 +320,10 @@ footer,
|
|||
.q-item.tx-snode,
|
||||
.q-item.tx-gov {
|
||||
.amount span {
|
||||
color: #43bd43;
|
||||
color: $oxen-navy;
|
||||
&:before {
|
||||
content: "+";
|
||||
color: #43bd43;
|
||||
color: $oxen-navy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -332,11 +337,11 @@ footer,
|
|||
.q-item.tx-out,
|
||||
.q-item.tx-pending {
|
||||
.amount span {
|
||||
color: white;
|
||||
// color: white;
|
||||
&:before {
|
||||
content: "-";
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
// color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -360,8 +365,12 @@ footer,
|
|||
}
|
||||
|
||||
.q-menu {
|
||||
background: #222;
|
||||
color:#cecece;
|
||||
background: white;
|
||||
color: $oxen-navy !important;
|
||||
|
||||
* {
|
||||
color: $oxen-navy;
|
||||
}
|
||||
|
||||
.q-list-separator > .q-item-division + .q-item-division, .q-item-division + .q-separator {
|
||||
border-top: 1px solid #333;
|
||||
|
@ -369,15 +378,25 @@ footer,
|
|||
}
|
||||
|
||||
.menu-list {
|
||||
.q-item * {
|
||||
color: white;
|
||||
}
|
||||
|
||||
background: white;
|
||||
|
||||
.q-item * {
|
||||
color: $oxen-navy;
|
||||
}
|
||||
}
|
||||
|
||||
.context-menu-list {
|
||||
min-width: 150px;
|
||||
max-height: 300px;
|
||||
}
|
||||
|
||||
.confirm-tx-card {
|
||||
color: "primary";
|
||||
width: 450px;
|
||||
max-width: 450x;
|
||||
|
||||
color: $oxen-navy !important;
|
||||
|
||||
.confirm-list {
|
||||
.q-item {
|
||||
max-height: 100%;
|
||||
|
@ -389,7 +408,7 @@ footer,
|
|||
}
|
||||
|
||||
.label {
|
||||
color: #cecece;
|
||||
color: $oxen-purple;
|
||||
padding-right: 6px;
|
||||
}
|
||||
.address-value {
|
||||
|
@ -398,20 +417,14 @@ footer,
|
|||
|
||||
.confirm-send-btn {
|
||||
color: white;
|
||||
background: $positive;
|
||||
background: $primary;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.header-popover {
|
||||
background: $primary;
|
||||
color: white;
|
||||
background: white;
|
||||
max-width: 250px !important;
|
||||
// padding-top: 4px;
|
||||
|
||||
// .q-list-separator > .q-item-division + .q-item-division, .q-item-division + .q-separator {
|
||||
// border-top: 1px solid $loki-green-dark-solid;
|
||||
// }
|
||||
}
|
||||
|
||||
.modal.minimized {
|
||||
|
@ -427,7 +440,6 @@ footer,
|
|||
|
||||
.modal {
|
||||
color: #cecece;
|
||||
background-color: $dark;
|
||||
|
||||
.modal-header {
|
||||
margin-top: 6px;
|
||||
|
@ -436,10 +448,6 @@ footer,
|
|||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.modal-content,
|
||||
.modal-body {
|
||||
background: $loki-black-80;
|
||||
}
|
||||
|
||||
.q-header {
|
||||
|
||||
|
@ -452,9 +460,22 @@ footer,
|
|||
|
||||
}
|
||||
|
||||
.q-toolbar {
|
||||
background-color: $oxen-navy;
|
||||
}
|
||||
|
||||
.header {
|
||||
color: $oxen-navy;
|
||||
}
|
||||
|
||||
.detail-page {
|
||||
color: $oxen-navy;
|
||||
}
|
||||
|
||||
.q-radio {
|
||||
color: $oxen-navy;
|
||||
svg {
|
||||
color: #cecece;
|
||||
color: $oxen-navy;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -463,20 +484,30 @@ footer,
|
|||
color: white;
|
||||
|
||||
.qr-code-card {
|
||||
background-color: $dark;
|
||||
background-color: white;
|
||||
}
|
||||
}
|
||||
|
||||
.loki-green {
|
||||
background: $loki-green;
|
||||
.oxen-light-teal {
|
||||
background: $oxen-light-teal;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.oxen-navy {
|
||||
background: $oxen-navy;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.oxen-teal {
|
||||
background: $oxen-teal;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.startup-icons {
|
||||
.solid {
|
||||
color:$loki-green-solid;
|
||||
color:$oxen-teal;
|
||||
g,path {
|
||||
fill: $loki-green-solid;
|
||||
fill: $oxen-teal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -489,37 +520,52 @@ footer,
|
|||
|
||||
.navigation {
|
||||
.q-btn {
|
||||
background: $oxen-navy;
|
||||
color: white;
|
||||
background: $loki-black-90;
|
||||
|
||||
.q-icon {
|
||||
color: $oxen-teal;
|
||||
}
|
||||
}
|
||||
|
||||
.router-link-exact-active > .q-btn {
|
||||
background: $loki-green;
|
||||
color: $oxen-navy
|
||||
background: $oxen-teal;
|
||||
|
||||
.q-icon {
|
||||
color: $oxen-navy;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.truncate-item {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.wallet-list {
|
||||
.q-item-label {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.q-item {
|
||||
background: $secondary;
|
||||
background: $oxen-navy;
|
||||
.wallet-icon {
|
||||
color: $tertiary;
|
||||
color: $oxen-teal;
|
||||
g,path {
|
||||
fill: $tertiary;
|
||||
fill: $oxen-teal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.q-item:hover, .q-item.selected {
|
||||
background: $primary !important;
|
||||
background: $oxen-purple !important;
|
||||
|
||||
.wallet-icon {
|
||||
color:$loki-green-solid;
|
||||
color: $oxen-teal;
|
||||
g,path {
|
||||
fill: $loki-green-solid;
|
||||
fill: $oxen-teal;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -529,21 +575,33 @@ footer,
|
|||
}
|
||||
}
|
||||
|
||||
.wallet-settings {
|
||||
.q-btn {
|
||||
color: $oxen-navy;
|
||||
}
|
||||
}
|
||||
|
||||
.receive {
|
||||
.q-list-header {
|
||||
color: #FFFFFF;
|
||||
|
||||
.list-header {
|
||||
color: $oxen-navy;
|
||||
}
|
||||
|
||||
.q-separator-component {
|
||||
background-color: $secondary;
|
||||
background-color: white;
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.primary-address {
|
||||
background: #3eb13e !important;
|
||||
background: $oxen-teal !important;
|
||||
border: none !important;
|
||||
|
||||
.q-item, .q-item-side {
|
||||
color: white;
|
||||
|
||||
.text-caption {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
.q-btn {
|
||||
|
@ -552,83 +610,153 @@ footer,
|
|||
}
|
||||
|
||||
.primary-address:hover {
|
||||
background: $loki-green-solid !important;
|
||||
background: #0ca69b !important;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.loki-list {
|
||||
.loki-list-item {
|
||||
background: #313131;
|
||||
.oxen-list {
|
||||
.oxen-list-item {
|
||||
background: white;
|
||||
-webkit-transition: background-color 0.2s ease-in;
|
||||
transition: background-color 0.2s ease-in;
|
||||
|
||||
font-size: 16px;
|
||||
color: #cecece;
|
||||
color: $oxen-navy;
|
||||
padding-top: 6px;
|
||||
padding-bottom: 6px;
|
||||
|
||||
margin: 0 16px;
|
||||
border-radius: 3px;
|
||||
border: 1px solid $oxen-navy;
|
||||
border-radius: 4px;
|
||||
|
||||
+ .loki-list-item {
|
||||
+ .oxen-list-item {
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.loki-list-item:hover {
|
||||
background: rgba(117,117,117,0.3);
|
||||
.text-caption {
|
||||
color: $oxen-navy;
|
||||
}
|
||||
|
||||
.oxen-list-item:hover {
|
||||
background: $off-grey;
|
||||
cursor: pointer;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.lns-record-list {
|
||||
.q-item-label.unlocked {
|
||||
color: white;
|
||||
}
|
||||
.record-type-title {
|
||||
font-weight: bold;
|
||||
margin-bottom: 40px;
|
||||
padding-bottom: 40px;
|
||||
color: $oxen-navy;
|
||||
}
|
||||
|
||||
.records-group {
|
||||
padding-bottom: 40px;
|
||||
}
|
||||
|
||||
.service-node-list {
|
||||
.q-item {
|
||||
cursor: pointer;
|
||||
background: #313131;
|
||||
color: $oxen-navy;
|
||||
background: white;
|
||||
-webkit-transition: background-color 0.2s ease-in;
|
||||
transition: background-color 0.2s ease-in;
|
||||
|
||||
border-radius: 3px;
|
||||
border: 1px solid $oxen-navy;
|
||||
border-radius: 4px;
|
||||
|
||||
+ .q-item {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.contrib-amounts {
|
||||
color: $oxen-navy;
|
||||
}
|
||||
}
|
||||
|
||||
.q-item-label {
|
||||
color: $oxen-navy;
|
||||
}
|
||||
|
||||
.q-item-sublabel {
|
||||
color: $loki-black-50;
|
||||
.fee {
|
||||
color: $oxen-navy;
|
||||
}
|
||||
|
||||
.q-item:hover {
|
||||
background: rgba(117,117,117,0.3);
|
||||
background: $off-grey;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.lokinet-expiration {
|
||||
width: 180px;
|
||||
}
|
||||
|
||||
.ons-record-list {
|
||||
.q-item {
|
||||
cursor: pointer;
|
||||
color: $oxen-navy;
|
||||
-webkit-transition: background-color 0.2s ease-in;
|
||||
transition: background-color 0.2s ease-in;
|
||||
|
||||
border: 1px solid $oxen-navy;
|
||||
border-radius: 4px;
|
||||
|
||||
.height {
|
||||
color: $oxen-navy;
|
||||
}
|
||||
|
||||
// we don't want to select button text (also a span) as well
|
||||
// this is the height text
|
||||
div > span {
|
||||
color: #1f1c47;
|
||||
}
|
||||
|
||||
+ .q-item {
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.q-item:hover {
|
||||
background: $off-grey;
|
||||
}
|
||||
}
|
||||
.update-renew-buttons {
|
||||
.q-btn:not(:first-child) {
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.tx-list {
|
||||
.transaction .main {
|
||||
border-left: 1px solid #252525;
|
||||
}
|
||||
}
|
||||
|
||||
.loki-field {
|
||||
.tab-desc {
|
||||
color: $oxen-navy;
|
||||
font-style: normal;
|
||||
b {
|
||||
color: $oxen-teal;
|
||||
font-style: italic;
|
||||
}
|
||||
}
|
||||
|
||||
.oxen-field {
|
||||
.content {
|
||||
border: 1px solid #484848;
|
||||
|
||||
background: white;
|
||||
-webkit-transition: background-color 0.2s ease-in, border-color 0.2s ease-in;
|
||||
transition: background-color 0.2s ease-in, border-color 0.2s ease-in;
|
||||
}
|
||||
|
||||
&:not(.disable):not(.disable-hover) {
|
||||
.content:hover {
|
||||
background: #2e2e2e;
|
||||
background: white;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -643,7 +771,7 @@ footer,
|
|||
}
|
||||
|
||||
.label {
|
||||
color: white;
|
||||
color: $oxen-navy;
|
||||
|
||||
.optional {
|
||||
color: #7C7C7C;
|
||||
|
@ -651,23 +779,16 @@ footer,
|
|||
}
|
||||
}
|
||||
|
||||
.service-node-registration, .prove-transaction, .check-transaction {
|
||||
.description{
|
||||
color: #b7b7b7;
|
||||
font-style: normal;
|
||||
b {
|
||||
color: white;
|
||||
font-style: italic;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.welcome {
|
||||
.q-footer {
|
||||
background: $secondary
|
||||
}
|
||||
}
|
||||
|
||||
.welcome-container {
|
||||
color: $oxen-navy;
|
||||
}
|
||||
|
||||
.address-book, .address-header {
|
||||
.q-item-label, .header {
|
||||
color: white;
|
||||
|
@ -683,6 +804,10 @@ footer,
|
|||
}
|
||||
}
|
||||
|
||||
.signature-dialog {
|
||||
color: $oxen-navy;
|
||||
}
|
||||
|
||||
.check-transaction {
|
||||
.good {
|
||||
color: #43bd43;
|
||||
|
@ -712,3 +837,46 @@ footer,
|
|||
.non-selectable {
|
||||
color: #979797;
|
||||
}
|
||||
|
||||
.created {
|
||||
color: $oxen-navy;
|
||||
|
||||
.wallet h6 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.address {
|
||||
text-align: center;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.seed-box {
|
||||
border: 1px solid white;
|
||||
border-radius: 3px;
|
||||
margin: 16px;
|
||||
padding: 16px;
|
||||
|
||||
div,
|
||||
h6 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.seed {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.warning {
|
||||
color: goldenrod;
|
||||
}
|
||||
}
|
||||
h6 {
|
||||
font-size: 18px;
|
||||
margin: 8px 0;
|
||||
font-weight: 450;
|
||||
}
|
||||
.advanced-options-label {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,9 +15,9 @@
|
|||
// It"s highly recommended to change the default colors
|
||||
// to match your app"s branding.
|
||||
|
||||
$primary = $loki-green
|
||||
$secondary = $loki-black-90
|
||||
$tertiary = $loki-black-80
|
||||
$primary = $oxen-teal
|
||||
$secondary = $oxen-light-teal
|
||||
$accent = $oxen-navy
|
||||
|
||||
$neutral = #E0E1E2
|
||||
$positive = #21BA45
|
||||
|
@ -26,10 +26,12 @@ $info = #31CCEC
|
|||
$warning = #F2C037
|
||||
|
||||
$loki-green = linear-gradient(180deg, #419B41 0%, #43BD43 100%)
|
||||
$loki-green-solid = #5BCA5B;
|
||||
$loki-green-dark-solid = #419B41;
|
||||
|
||||
$loki-black-90 = #0A0A0A
|
||||
$loki-black-80 = #252525
|
||||
$loki-black-60 = #313131
|
||||
$loki-black-50 = #7E7E7E;
|
||||
$oxen-navy = #1F1C47;
|
||||
$oxen-teal = #12C7BA;
|
||||
$oxen-light-teal = #DBF7F5;
|
||||
$oxen-purple = #654192;
|
||||
|
||||
$off-grey = #E8E8E8;
|
||||
|
||||
$loki-black-60 = #313131;
|
||||
|
|
|
@ -14,21 +14,23 @@
|
|||
// It"s highly recommended to change the default colors
|
||||
// to match your app"s branding.
|
||||
|
||||
$primary = $loki-green
|
||||
$secondary = $loki-black-90
|
||||
$tertiary = $loki-black-80
|
||||
// $primary = $loki-green
|
||||
// $secondary = $loki-black-90
|
||||
// $tertiary = $loki-black-80
|
||||
|
||||
$neutral = #E0E1E2
|
||||
$positive = #21BA45
|
||||
$negative = #DB2828
|
||||
$info = #31CCEC
|
||||
$warning = #F2C037
|
||||
// $neutral = #E0E1E2
|
||||
// $positive = #21BA45
|
||||
// $negative = #DB2828
|
||||
// $info = #31CCEC
|
||||
// $warning = #F2C037
|
||||
|
||||
$loki-green = linear-gradient(180deg, #419B41 0%, #43BD43 100%)
|
||||
$loki-green-solid = #5BCA5B;
|
||||
$loki-green-dark-solid = #419B41;
|
||||
// $loki-green = linear-gradient(180deg, #419B41 0%, #43BD43 100%)
|
||||
|
||||
$loki-black-90 = #0A0A0A
|
||||
$loki-black-80 = #252525
|
||||
$loki-black-60 = #313131
|
||||
$loki-black-50 = #7E7E7E;
|
||||
// $oxen-navy = #1F1C47;
|
||||
// $oxen-teal = #12C7BA;
|
||||
// $oxen-light-teal = #DBF7F5;
|
||||
|
||||
// $loki-black-90 = #0A0A0A
|
||||
// $loki-black-80 = #252525
|
||||
// $loki-black-60 = #313131
|
||||
// $loki-black-50 = #7E7E7E;
|
|
@ -20,7 +20,7 @@ export class Gateway extends EventEmitter {
|
|||
|
||||
let theme = LocalStorage.has("theme")
|
||||
? LocalStorage.getItem("theme")
|
||||
: "dark";
|
||||
: "light";
|
||||
this.app.store.commit("gateway/set_app_data", {
|
||||
config: {
|
||||
appearance: {
|
||||
|
@ -89,17 +89,13 @@ export class Gateway extends EventEmitter {
|
|||
message: msg,
|
||||
ok: {
|
||||
label: i18n.t(`dialog.${key}.ok`),
|
||||
color: "positive"
|
||||
color: "primary"
|
||||
},
|
||||
cancel: {
|
||||
flat: true,
|
||||
label: i18n.t("dialog.buttons.cancel"),
|
||||
color:
|
||||
this.app.store.state.gateway.app.config.appearance.theme === "dark"
|
||||
? "white"
|
||||
: "dark"
|
||||
},
|
||||
dark: this.app.store.state.gateway.app.config.appearance.theme === "dark"
|
||||
color: "grey"
|
||||
}
|
||||
})
|
||||
.onOk(() => {
|
||||
this.closeDialog = false;
|
||||
|
@ -194,13 +190,13 @@ export class Gateway extends EventEmitter {
|
|||
break;
|
||||
}
|
||||
|
||||
case "set_lns_status": {
|
||||
case "set_ons_status": {
|
||||
const data = { ...decrypted_data.data };
|
||||
if (data.i18n) {
|
||||
data.message = this.geti18n(data.i18n);
|
||||
}
|
||||
|
||||
this.app.store.commit("gateway/set_lns_status", data);
|
||||
this.app.store.commit("gateway/set_ons_status", data);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -237,6 +233,14 @@ export class Gateway extends EventEmitter {
|
|||
this.app.store.commit("gateway/set_check_transaction_status", data);
|
||||
break;
|
||||
}
|
||||
case "set_sign_status": {
|
||||
this.app.store.commit("gateway/set_sign_status", decrypted_data.data);
|
||||
break;
|
||||
}
|
||||
case "set_verify_status": {
|
||||
this.app.store.commit("gateway/set_verify_status", decrypted_data.data);
|
||||
break;
|
||||
}
|
||||
case "set_old_gui_import_status":
|
||||
this.app.store.commit(
|
||||
"gateway/set_old_gui_import_status",
|
||||
|
|
|
@ -243,7 +243,7 @@ export default {
|
|||
copyViewKey: "View Key kopieren",
|
||||
createNewWallet: "Neue Wallet erstellen",
|
||||
deleteWallet: "Wallet löschen",
|
||||
exit: "Loki GUI Wallet schliessen",
|
||||
exit: "Oxen GUI Wallet schliessen",
|
||||
importOldGUIWallet: "Wallets von alter GUI importieren",
|
||||
manageKeyImages: "Key Images verwalten",
|
||||
openWallet: "Wallet öffnen",
|
||||
|
@ -332,7 +332,7 @@ export default {
|
|||
noKeyImageExport: "Keine Key Images zum Exportieren gefunden",
|
||||
usingLocalNode:
|
||||
"Zugang zur Remote Node nicht möglich, wechsle zur lokalen Node",
|
||||
usingRemoteNode: "llokid nicht gefunden, benutze eine Remote Node"
|
||||
usingRemoteNode: "loxend nicht gefunden, benutze eine Remote Node"
|
||||
}
|
||||
},
|
||||
placeholders: {
|
||||
|
@ -408,9 +408,9 @@ export default {
|
|||
destinationUnknown: "Ziel unbekannt",
|
||||
editAddressBookEntry: "Adressbucheintrag bearbeiten",
|
||||
loadingSettings: "Einstellungen werden geladen",
|
||||
lokiBalance: "Guthaben",
|
||||
lokiUnlockedBalance: "frei verfügbares Guthaben",
|
||||
lokiUnlockedShort: "frei verfügbar",
|
||||
oxenBalance: "Guthaben",
|
||||
oxenUnlockedBalance: "frei verfügbares Guthaben",
|
||||
oxenUnlockedShort: "frei verfügbar",
|
||||
noTransactionsFound: "Keine Transaktionen gefunden",
|
||||
notes: "Notizen",
|
||||
numberOfUnspentOutputs: "Anzahl der unspent outputs",
|
||||
|
|
|
@ -12,6 +12,7 @@ export default {
|
|||
close: "CLOSE",
|
||||
contacts: "CONTACTS",
|
||||
copyAddress: "COPY ADDRESS",
|
||||
copyData: "COPY DATA",
|
||||
copySignature: "COPY SIGNATURE",
|
||||
createWallet: "CREATE WALLET",
|
||||
decrypt: "DECRYPT",
|
||||
|
@ -21,7 +22,7 @@ export default {
|
|||
generate: "GENERATE",
|
||||
import: "IMPORT",
|
||||
importWallet: "IMPORT WALLET | IMPORT WALLETS",
|
||||
lns: "LOKI NAME SERVICE",
|
||||
ons: "OXEN NAME SERVICE",
|
||||
max: "MAX",
|
||||
min: "MIN",
|
||||
next: "NEXT",
|
||||
|
@ -42,10 +43,12 @@ export default {
|
|||
settings: "SETTINGS",
|
||||
showQRCode: "SHOW QR CODE",
|
||||
showTxDetails: "SHOW TX DETAILS",
|
||||
sign: "SIGN",
|
||||
stake: "STAKE",
|
||||
sweepAll: "SWEEP ALL",
|
||||
unlock: "UNLOCK",
|
||||
update: "UPDATE",
|
||||
verify: "VERIFY",
|
||||
viewOnExplorer: "VIEW ON EXPLORER"
|
||||
},
|
||||
dialog: {
|
||||
|
@ -88,15 +91,20 @@ export default {
|
|||
message: "Are you sure you want to exit?",
|
||||
ok: "EXIT"
|
||||
},
|
||||
exportTransfers: {
|
||||
title: "Export Transfers to CSV",
|
||||
message: "Do you want to export transfers?",
|
||||
export: "Export"
|
||||
},
|
||||
keyImages: {
|
||||
title: "{type} key images",
|
||||
message: "Do you want to {type} key images?",
|
||||
export: "Export",
|
||||
import: "Import"
|
||||
},
|
||||
lnsUpdate: {
|
||||
title: "Update LNS record",
|
||||
message: "Do you want to update the LNS record?",
|
||||
onsUpdate: {
|
||||
title: "Update ONS record",
|
||||
message: "Do you want to update the ONS record?",
|
||||
ok: "UPDATE"
|
||||
},
|
||||
noPassword: {
|
||||
|
@ -139,6 +147,11 @@ export default {
|
|||
message: "Do you want to view your private keys?",
|
||||
ok: "SHOW"
|
||||
},
|
||||
signature: {
|
||||
title: "Signature",
|
||||
message:
|
||||
"Copy the data signed by your primary address's private key below"
|
||||
},
|
||||
stake: {
|
||||
title: "Stake",
|
||||
message: "Do you want to stake?",
|
||||
|
@ -202,8 +215,12 @@ export default {
|
|||
confirmPassword: "CONFIRM PASSWORD",
|
||||
daemonLogLevel: "DAEMON LOG LEVEL",
|
||||
daemonP2pPort: "DAEMON P2P PORT",
|
||||
data: "DATA",
|
||||
dataStoragePath: "DATA STORAGE PATH",
|
||||
decryptRecord: "DECRYPT RECORD",
|
||||
exportTransfers: {
|
||||
exportDirectory: "CSV EXPORT DIRECTORY"
|
||||
},
|
||||
filter: "FILTER",
|
||||
filterTransactionType: "FILTER BY TRANSACTION TYPE",
|
||||
internalWalletPort: "INTERNAL WALLET PORT",
|
||||
|
@ -213,7 +230,7 @@ export default {
|
|||
},
|
||||
limitDownloadRate: "LIMIT DOWNLOAD RATE",
|
||||
limitUploadRate: "LIMIT UPLOAD RATE",
|
||||
lnsType: "LNS RECORD TYPE",
|
||||
onsType: "ONS RECORD TYPE",
|
||||
localDaemonIP: "LOCAL DAEMON IP",
|
||||
localDaemonPort: "LOCAL DAEMON PORT",
|
||||
lokinetFullAddress: "LOKINET FULL ADDRESS",
|
||||
|
@ -239,6 +256,7 @@ export default {
|
|||
sessionId: "SESSION ID",
|
||||
signature: "SIGNATURE",
|
||||
transactionId: "TRANSACTION ID",
|
||||
walletAddress: "WALLET ADDRESS",
|
||||
walletFile: "WALLET FILE",
|
||||
walletLogLevel: "WALLET LOG LEVEL",
|
||||
walletName: "WALLET NAME",
|
||||
|
@ -282,7 +300,8 @@ export default {
|
|||
copyViewKey: "Copy view key",
|
||||
createNewWallet: "Create new wallet",
|
||||
deleteWallet: "Delete Wallet",
|
||||
exit: "Exit Loki GUI Wallet",
|
||||
exportTransfers: "Export Transfers",
|
||||
exit: "Exit Oxen GUI Wallet",
|
||||
importOldGUIWallet: "Import wallets from old GUI",
|
||||
manageKeyImages: "Manage Key Images",
|
||||
openWallet: "Open wallet",
|
||||
|
@ -304,13 +323,14 @@ export default {
|
|||
backupOwnerCopied: "Backup owner copied to clipboard",
|
||||
bannedPeer: "Banned {host} until {time}",
|
||||
copied: "{item} copied to clipboard",
|
||||
decryptedLNSRecord: "Successfully decrypted LNS Record for {name}",
|
||||
decryptedONSRecord: "Successfully decrypted ONS Record for {name}",
|
||||
exportTransfers: "Transfers exported to {filename}",
|
||||
itemSaved: "{item} saved to {filename}",
|
||||
keyImages: {
|
||||
exported: "Key images exported to {filename}",
|
||||
imported: "Key images imported"
|
||||
},
|
||||
lnsRecordUpdated: "LNS Record was successfully updated",
|
||||
onsRecordUpdated: "ONS Record was successfully updated",
|
||||
lokinetAddressCopied: "Full lokinet address copied",
|
||||
lokinetNameCopied: "Lokinet name copied",
|
||||
passwordUpdated: "Password updated",
|
||||
|
@ -324,8 +344,10 @@ export default {
|
|||
serviceNodeInfoFilled: "Service node key and min amount filled",
|
||||
sessionIdCopied: "Session ID copied to clipboard",
|
||||
signatureCopied: "Signature copied to clipboard",
|
||||
signatureVerified: "Signature verified",
|
||||
stakeSuccess: "Successfully staked",
|
||||
transactionNotesSaved: "Transaction notes saved"
|
||||
transactionNotesSaved: "Transaction notes saved",
|
||||
walletCopied: "Wallet address copied to clipboard"
|
||||
},
|
||||
errors: {
|
||||
banningPeer: "Error banning peer",
|
||||
|
@ -335,7 +357,7 @@ export default {
|
|||
copyWalletFail: "Failed to copy wallet",
|
||||
copyingPrivateKeys: "Error copying private keys",
|
||||
dataPathNotFound: "Data storage path not found",
|
||||
decryptLNSRecord: "Failed to decrypt LNS Record for {name}",
|
||||
decryptONSRecord: "Failed to decrypt ONS Record for {name}",
|
||||
differentNetType: "Remote node is using a different nettype",
|
||||
enterSeedWords: "Enter seed words",
|
||||
enterTransactionId: "Enter transaction ID",
|
||||
|
@ -343,6 +365,7 @@ export default {
|
|||
enterWalletName: "Enter a wallet name",
|
||||
enterName: "Enter a name",
|
||||
errorSavingItem: "Error saving {item}",
|
||||
exportTransfers: "Error exporting transfers",
|
||||
failedServiceNodeUnlock: "Failed to unlock service node",
|
||||
failedToSetLanguage: "Failed to set language: {lang}",
|
||||
failedWalletImport: "Failed to import wallet",
|
||||
|
@ -370,6 +393,7 @@ export default {
|
|||
"Please enter the service node registration command",
|
||||
invalidServiceNodeKey: "Service node key not valid",
|
||||
invalidSessionId: "Session ID not valid",
|
||||
invalidSignature: "Invalid signature",
|
||||
invalidWalletPath: "Invalid wallet path",
|
||||
keyImages: {
|
||||
exporting: "Error exporting key images",
|
||||
|
@ -389,21 +413,24 @@ export default {
|
|||
zeroAmount: "Amount must be greater than zero"
|
||||
},
|
||||
warnings: {
|
||||
noExportTransfers: "No transfers found to export",
|
||||
noKeyImageExport: "No key images found to export",
|
||||
usingLocalNode: "Could not access remote node, switching to local only",
|
||||
usingRemoteNode: "lokid not found, using remote node"
|
||||
usingRemoteNode: "oxend not found, using remote node"
|
||||
}
|
||||
},
|
||||
placeholders: {
|
||||
additionalNotes: "Additional notes",
|
||||
addressBookName: "Name that belongs to this address",
|
||||
addressOfSigner: "Public wallet address of signer",
|
||||
dataToSign: "Data you want to sign with your primary address's private key",
|
||||
filterTx: "Enter an ID, name, address or amount",
|
||||
hexCharacters: "{count} hexadecimal characters",
|
||||
lnsName: "The name to purchase via Loki Name Service",
|
||||
lnsBackupOwner: "The wallet address of the backup owner",
|
||||
lnsDecryptName: "A LNS name that belongs to you",
|
||||
onsName: "The name to purchase via Oxen Name Service",
|
||||
onsBackupOwner: "The wallet address of the backup owner",
|
||||
onsDecryptName: "A ONS name that belongs to you",
|
||||
lokinetFullAddress:
|
||||
"Full lokinet address to map LNS name to (without .loki)",
|
||||
"Full lokinet address to map ONS name to (without .loki)",
|
||||
mnemonicSeed: "25 (or 24) word mnemonic seed",
|
||||
pasteTransactionId: "Paste transaction ID",
|
||||
pasteTransactionProof: "Paste transaction proof",
|
||||
|
@ -411,8 +438,11 @@ export default {
|
|||
"Optional message against which the signature is signed",
|
||||
recipientWalletAddress: "Recipient's wallet address",
|
||||
selectAFile: "Please select a file",
|
||||
sessionId: "The Session ID to link to Loki Name Service",
|
||||
sessionId: "The Session ID to link to Oxen Name Service",
|
||||
signature: "Signature to verify",
|
||||
transactionNotes: "Additional notes to locally attach to the transaction",
|
||||
unsignedData: "The data as it should look before it was signed",
|
||||
walletAddress: "Wallet address to map ONS name to",
|
||||
walletName: "A name for your wallet",
|
||||
walletPassword: "An optional password for the wallet"
|
||||
},
|
||||
|
@ -435,6 +465,7 @@ export default {
|
|||
bannedUntil: "Banned until {time}"
|
||||
},
|
||||
blockHeight: "Height",
|
||||
cannotSign: "You cannot sign with a view only wallet.",
|
||||
checkTransaction: {
|
||||
description:
|
||||
"Verify that funds were paid to an address by supplying the transaction ID, the recipient address, the message used for signing and the signature.\nFor a 'Spend Proof' you dont need to provide the recipient address.",
|
||||
|
@ -473,22 +504,27 @@ export default {
|
|||
destinationUnknown: "Destination Unknown",
|
||||
editAddressBookEntry: "Edit address book entry",
|
||||
expirationHeight: "Expiration height",
|
||||
lns: {
|
||||
nextPayout: "Next payout",
|
||||
ons: {
|
||||
sessionID: "Session ID",
|
||||
wallet: "Wallet Address",
|
||||
lokinetName1Year: "Lokinet Name 1 year",
|
||||
lokinetNameXYears: "Lokinet Name {years} years",
|
||||
prices: "LNS Prices:"
|
||||
prices: "ONS Prices:"
|
||||
},
|
||||
lnsPurchaseDescription:
|
||||
"Purchase or update an LNS record. If you purchase a name, it may take a minute or two for it to show up in the list.",
|
||||
lnsDescription:
|
||||
"Here you can find all the LNS names owned by this wallet. Decrypting a record you own will return the name and value of that LNS record.",
|
||||
onsPurchaseDescription:
|
||||
"Purchase or update an ONS record. If you purchase a name, it may take a minute or two for it to show up in the list.",
|
||||
onsDescription:
|
||||
"Here you can find all the ONS names owned by this wallet. Decrypting a record you own will return the name and value of that ONS record.",
|
||||
hardwareWallet: "Hardware wallet",
|
||||
hardwareWallets: "Hardware wallets",
|
||||
loadingSettings: "Loading settings",
|
||||
lokiBalance: "Balance",
|
||||
oxenBalance: "Balance",
|
||||
lokinetNameDescription:
|
||||
"Purchase or update a name on Lokinet. If you purchase a name it may take a minute or two for it to show up in the list. To learn more about lokinet visit: ",
|
||||
lokiUnlockedBalance: "Unlocked balance",
|
||||
lokiUnlockedShort: "Unlocked",
|
||||
oxenAccumulatedRewards: "Accumulated rewards",
|
||||
oxenUnlockedBalance: "Unlocked balance",
|
||||
oxenUnlockedShort: "Unlocked",
|
||||
me: "Me",
|
||||
noTransactionsFound: "No transactions found",
|
||||
notes: "Notes",
|
||||
|
@ -511,6 +547,7 @@ export default {
|
|||
recentIncomingTransactionsToAddress:
|
||||
"Recent incoming transactions to this address",
|
||||
recentTransactionsWithAddress: "Recent transactions with this address",
|
||||
regularWallets: "Regular wallets",
|
||||
rescanModalDescription:
|
||||
"Select full rescan or rescan of spent outputs only.",
|
||||
saveSeedWarning: "Please copy and save these in a secure location!",
|
||||
|
@ -518,7 +555,7 @@ export default {
|
|||
seedWords: "Seed words",
|
||||
selectLanguage: "Select language",
|
||||
serviceNodeContributionDescription:
|
||||
"Staking contributes to the safety of the Loki network. For your contribution, you earn LOKI. Once staked, you will have to wait either 15 or 30 days to have your Loki unlocked, depending on if a stake was unlocked by a contributor or the node was deregistered. To learn more about staking, please visit the",
|
||||
"Staking contributes to the safety of the Oxen network. For your contribution, you earn OXEN. Once staked, you will have to wait either 15 or 30 days to have your OXEN unlocked, depending on if a stake was unlocked by a contributor or the node was deregistered. To learn more about staking, please visit the documentation on the",
|
||||
serviceNodeRegistrationDescription:
|
||||
'Enter the {registerCommand} command produced by the daemon that is registering to become a Service Node using the "{prepareCommand}" command',
|
||||
serviceNodeStartStakingDescription:
|
||||
|
@ -540,7 +577,10 @@ export default {
|
|||
stakingRequirement: "Staking requirement",
|
||||
totalContributed: "Total contributed"
|
||||
},
|
||||
signAndVerifyDescription:
|
||||
"Sign data with your primary address's private key or verify a signature against a public address.",
|
||||
spendKey: "Spend key",
|
||||
stake: "Staking",
|
||||
startingDaemon: "Starting daemon",
|
||||
startingWallet: "Starting wallet",
|
||||
switchToDateSelect: "Switch to date select",
|
||||
|
@ -585,20 +625,24 @@ export default {
|
|||
addressDetails: "Address details",
|
||||
advanced: {
|
||||
checkTransaction: "CHECK TRANSACTION",
|
||||
prove: "PROVE"
|
||||
prove: "PROVE",
|
||||
signAndVerify: "SIGN/VERIFY",
|
||||
sign: "Sign",
|
||||
verify: "Verify"
|
||||
},
|
||||
availableForContribution: "Service nodes available for contribution",
|
||||
changePassword: "Change password",
|
||||
configure: "Configure",
|
||||
currentlyStakedNodes: "Currently staked nodes",
|
||||
lnsRecordDetails: "LNS record details",
|
||||
lnsSessionRecords: "Session records",
|
||||
lnsLokinetRecords: "Lokinet records",
|
||||
onsRecordDetails: "ONS record details",
|
||||
onsSessionRecords: "Session records",
|
||||
onsLokinetRecords: "Lokinet records",
|
||||
onsWalletRecords: "Wallet records",
|
||||
privateKeys: "Private keys",
|
||||
rescanWallet: "Rescan wallet",
|
||||
lns: {
|
||||
ons: {
|
||||
purchase: "PURCHASE",
|
||||
myLns: "MY LNS"
|
||||
myOns: "MY ONS"
|
||||
},
|
||||
serviceNode: {
|
||||
registration: "REGISTRATION",
|
||||
|
|
|
@ -242,7 +242,7 @@ export default {
|
|||
copyViewKey: "Copiar clave de visualización",
|
||||
createNewWallet: "Crear nuevo monedero",
|
||||
deleteWallet: "Eliminar monedero",
|
||||
exit: "Cerrar la interfaz del monedero Loki",
|
||||
exit: "Cerrar la interfaz del monedero Oxen",
|
||||
importOldGUIWallet: "Importar monedero de una interfaz gráfica antigua",
|
||||
manageKeyImages: "Administrar Imágenes de Clave",
|
||||
openWallet: "Abrir monedero",
|
||||
|
@ -330,7 +330,7 @@ export default {
|
|||
noKeyImageExport: "No se han encontrado claves para exportar",
|
||||
usingLocalNode:
|
||||
"No se ha podido acceder al nodo remoto, volviendo al modo local",
|
||||
usingRemoteNode: "lokid no encontrado, utilizando nodo remoto"
|
||||
usingRemoteNode: "oxend no encontrado, utilizando nodo remoto"
|
||||
}
|
||||
},
|
||||
placeholders: {
|
||||
|
@ -403,9 +403,9 @@ export default {
|
|||
destinationUnknown: "Destino Desconocido",
|
||||
editAddressBookEntry: "Modificar un registro de la libreta de direcciones",
|
||||
loadingSettings: "Cargando configuración",
|
||||
lokiBalance: "Saldo",
|
||||
lokiUnlockedBalance: "Saldo libre",
|
||||
lokiUnlockedShort: "Libre",
|
||||
oxenBalance: "Saldo",
|
||||
oxenUnlockedBalance: "Saldo libre",
|
||||
oxenUnlockedShort: "Libre",
|
||||
noTransactionsFound: "No se han encontrado transacciones",
|
||||
notes: "Notas",
|
||||
numberOfUnspentOutputs: "Número de salidas no gastadas",
|
||||
|
@ -431,7 +431,7 @@ export default {
|
|||
seedWords: "Palabras semilla",
|
||||
selectLanguage: "Escoja un idioma",
|
||||
serviceNodeRegistrationDescription:
|
||||
'Introduzca la orden {registerCommand} generada por el servicio (lokid) que se está intentado registrar como Nodo de Servicio usando la instrucción "{prepareCommand}"',
|
||||
'Introduzca la orden {registerCommand} generada por el servicio (oxend) que se está intentado registrar como Nodo de Servicio usando la instrucción "{prepareCommand}"',
|
||||
spendKey: "Clave de gasto",
|
||||
startingDaemon: "Iniciando servicio",
|
||||
startingWallet: "Iniciando monedero",
|
||||
|
|
|
@ -244,7 +244,7 @@ export default {
|
|||
copyViewKey: "Copier la clé de visibilité",
|
||||
createNewWallet: "Créer un nouveau portefeuille",
|
||||
deleteWallet: "Supprimer le portefeuille",
|
||||
exit: "Quitter le portefeuille Loki GUI",
|
||||
exit: "Quitter le portefeuille Oxen GUI",
|
||||
importOldGUIWallet: "Importer le portefeuille depuis l’ancien GUI",
|
||||
manageKeyImages: "Gérer les images clés",
|
||||
openWallet: "Ouvrir le portefeuille",
|
||||
|
@ -334,7 +334,7 @@ export default {
|
|||
noKeyImageExport: "Aucune clé image n'a été trouvé pour l'export",
|
||||
usingLocalNode:
|
||||
"Impossible d'accéder au nœud distant, basculement en local uniquement",
|
||||
usingRemoteNode: "lokid introuvable, utilisation du nœud distant"
|
||||
usingRemoteNode: "oxend introuvable, utilisation du nœud distant"
|
||||
}
|
||||
},
|
||||
placeholders: {
|
||||
|
@ -410,9 +410,9 @@ export default {
|
|||
destinationUnknown: "Destination inconnue",
|
||||
editAddressBookEntry: "Modifiez l'entrée du carnet d'adresses",
|
||||
loadingSettings: "Chargement des réglages",
|
||||
lokiBalance: "Solde",
|
||||
lokiUnlockedBalance: "Solde débloqué",
|
||||
lokiUnlockedShort: "Débloqué",
|
||||
oxenBalance: "Solde",
|
||||
oxenUnlockedBalance: "Solde débloqué",
|
||||
oxenUnlockedShort: "Débloqué",
|
||||
noTransactionsFound: "Aucune transaction trouvée",
|
||||
notes: "Notes",
|
||||
numberOfUnspentOutputs: "Nombre de sorties non dépensées",
|
||||
|
|
|
@ -330,7 +330,7 @@ export default {
|
|||
noKeyImageExport: "Nenhuma chave de imagem encontrada para exportar",
|
||||
usingLocalNode:
|
||||
"Não foi possível aceder ao nódulo remoto, mudando para nódulo local apenas",
|
||||
usingRemoteNode: "lokid não encontrado, utilizando nódulo remoto"
|
||||
usingRemoteNode: "oxend não encontrado, utilizando nódulo remoto"
|
||||
}
|
||||
},
|
||||
placeholders: {
|
||||
|
@ -404,9 +404,9 @@ export default {
|
|||
destinationUnknown: "Destino Desconhecido",
|
||||
editAddressBookEntry: "Editar registo do livro de endereços",
|
||||
loadingSettings: "Carregando configurações",
|
||||
lokiBalance: "Saldo",
|
||||
lokiUnlockedBalance: "Saldo desbloqueado",
|
||||
lokiUnlockedShort: "Desbloqueado",
|
||||
oxenBalance: "Saldo",
|
||||
oxenUnlockedBalance: "Saldo desbloqueado",
|
||||
oxenUnlockedShort: "Desbloqueado",
|
||||
noTransactionsFound: "Nenhuma transação encontrada",
|
||||
notes: "Notas",
|
||||
numberOfUnspentOutputs: "Número de outputs não gastos",
|
||||
|
|
|
@ -241,7 +241,7 @@ export default {
|
|||
copyViewKey: "Копировать Ключ Просмотра",
|
||||
createNewWallet: "Создать новый кошелек",
|
||||
deleteWallet: "Удалить Кошелек",
|
||||
exit: "Закрыть Кошелек Loki",
|
||||
exit: "Закрыть Кошелек Oxen",
|
||||
importOldGUIWallet: "Импортировать кошельки из старого GUI",
|
||||
manageKeyImages: "Управлять Ключевыми Образами",
|
||||
openWallet: "Открыть кошелек",
|
||||
|
@ -329,7 +329,7 @@ export default {
|
|||
noKeyImageExport: "Не найдено ключевых образов для экспорта",
|
||||
usingLocalNode:
|
||||
"Не удалось подключиться к удаленной ноде, переключаемся на локальную ноду",
|
||||
usingRemoteNode: "Не найден файл lokid, используется удаленная нода"
|
||||
usingRemoteNode: "Не найден файл oxend, используется удаленная нода"
|
||||
}
|
||||
},
|
||||
placeholders: {
|
||||
|
@ -403,9 +403,9 @@ export default {
|
|||
destinationUnknown: "Назначение Неизвестно",
|
||||
editAddressBookEntry: "Редактировать запись адресной книги",
|
||||
loadingSettings: "Загрузка настроек",
|
||||
lokiBalance: "Баланс",
|
||||
lokiUnlockedBalance: "Разблокированый баланс",
|
||||
lokiUnlockedShort: "Разблокировано",
|
||||
oxenBalance: "Баланс",
|
||||
oxenUnlockedBalance: "Разблокированый баланс",
|
||||
oxenUnlockedShort: "Разблокировано",
|
||||
noTransactionsFound: "Транзакции не найдены",
|
||||
notes: "Заметки",
|
||||
numberOfUnspentOutputs: "Количество непотраченных выходов",
|
||||
|
|
|
@ -6,12 +6,24 @@
|
|||
<MainMenu :disable-switch-wallet="true" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<q-btn class="cancel" icon="reply" flat round dense @click="cancel()" />
|
||||
<q-btn
|
||||
class="cancel"
|
||||
icon="reply"
|
||||
flat
|
||||
round
|
||||
dense
|
||||
@click="cancel()"
|
||||
/>
|
||||
</template>
|
||||
<q-toolbar-title v-if="page_title == 'Loki'" class="flex items-center justify-center">
|
||||
<img src="loki.svg" height="32" />
|
||||
<q-toolbar-title
|
||||
v-if="page_title == 'Oxen'"
|
||||
class="flex items-center justify-center"
|
||||
>
|
||||
<img src="oxen-white.svg" height="32" />
|
||||
</q-toolbar-title>
|
||||
<q-toolbar-title v-else class="flex items-center justify-center">{{ page_title }}</q-toolbar-title>
|
||||
<q-toolbar-title v-else class="flex items-center justify-center">{{
|
||||
page_title
|
||||
}}</q-toolbar-title>
|
||||
</q-toolbar>
|
||||
</q-header>
|
||||
|
||||
|
@ -58,7 +70,7 @@ export default {
|
|||
|
||||
default:
|
||||
case "wallet-select":
|
||||
return "Loki";
|
||||
return "Oxen";
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
<q-layout view="hHh Lpr lFf">
|
||||
<q-header class="shift-title">
|
||||
<MainMenu />
|
||||
<q-toolbar-title>
|
||||
<div class="flex items-center justify-center" style="margin-top:7px">
|
||||
<img src="loki.svg" height="32" />
|
||||
<q-toolbar-title style="background: white;">
|
||||
<div class="flex items-center justify-center" style="margin:8px">
|
||||
<img src="oxen.svg" height="32" />
|
||||
</div>
|
||||
</q-toolbar-title>
|
||||
</q-header>
|
||||
|
@ -27,16 +27,40 @@
|
|||
/>
|
||||
</router-link>
|
||||
<router-link to="/wallet/receive">
|
||||
<q-btn class="large-btn" :label="$t('buttons.receive')" size="md" icon-right="save_alt" align="between" />
|
||||
<q-btn
|
||||
class="large-btn"
|
||||
:label="$t('buttons.receive')"
|
||||
size="md"
|
||||
icon-right="save_alt"
|
||||
align="between"
|
||||
/>
|
||||
</router-link>
|
||||
<router-link to="/wallet/servicenode">
|
||||
<q-btn class="large-btn" :label="$t('buttons.serviceNode')" size="md" icon-right="router" align="between" />
|
||||
<q-btn
|
||||
class="large-btn"
|
||||
:label="$t('buttons.serviceNode')"
|
||||
size="md"
|
||||
icon-right="router"
|
||||
align="between"
|
||||
/>
|
||||
</router-link>
|
||||
<router-link to="/wallet/lns">
|
||||
<q-btn class="large-btn" :label="$t('buttons.lns')" size="md" icon-right="text_fields" align="between" />
|
||||
<router-link to="/wallet/ons">
|
||||
<q-btn
|
||||
class="large-btn"
|
||||
:label="$t('buttons.ons')"
|
||||
size="md"
|
||||
icon-right="text_fields"
|
||||
align="between"
|
||||
/>
|
||||
</router-link>
|
||||
<router-link to="/wallet/advanced">
|
||||
<q-btn class="large-btn" :label="$t('buttons.advanced')" size="md" icon-right="tune" align="between" />
|
||||
<q-btn
|
||||
class="large-btn"
|
||||
:label="$t('buttons.advanced')"
|
||||
size="md"
|
||||
icon-right="tune"
|
||||
align="between"
|
||||
/>
|
||||
</router-link>
|
||||
<router-link to="/wallet/addressbook" class="address">
|
||||
<q-btn class="single-icon" size="md" icon="person" />
|
||||
|
|
|
@ -1,27 +1,52 @@
|
|||
export default {
|
||||
methods: {
|
||||
getMinContribution(node) {
|
||||
const MAX_NUMBER_OF_CONTRIBUTORS = 4;
|
||||
// This is calculated in the same way it is calculated on the LokiBlocks site
|
||||
const openContributionRemaining = this.openForContribution(node);
|
||||
const minContributionAtomicUnits =
|
||||
!node.funded && node.contributors.length < MAX_NUMBER_OF_CONTRIBUTORS
|
||||
? openContributionRemaining /
|
||||
(MAX_NUMBER_OF_CONTRIBUTORS - node.contributors.length)
|
||||
: 0;
|
||||
const minContributionLoki = minContributionAtomicUnits / 1e9;
|
||||
// ceiling to 4 decimal places
|
||||
return minContributionLoki.toFixed(4);
|
||||
// Returns the atomic, unfilled, reserved contributions for the given wallet
|
||||
getUnfilledReservedContribution(node, addr) {
|
||||
for (const contributor of node.contributors) {
|
||||
if (contributor.address === addr && contributor.amount === 0 && contributor.reserved > 0) {
|
||||
return contributor.reserved;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
openForContribution(node) {
|
||||
const openContributionRemaining =
|
||||
getMinContribution(node, myaddr) {
|
||||
if (node.funded) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const MAX_NUMBER_OF_CONTRIBUTORS = 10;
|
||||
// If we have a reserved spot then that is our minimum:
|
||||
let minContributionAtomicUnits = this.getUnfilledReservedContribution(node, myaddr);
|
||||
// Otherwise we can contribute our fair share of whatever amount is left (i.e. REMAINING/N
|
||||
// when there are N available spots).
|
||||
if (minContributionAtomicUnits === 0 && node.contributors.length < MAX_NUMBER_OF_CONTRIBUTORS) {
|
||||
const openContributionRemaining = this.openForContribution(node);
|
||||
|
||||
let contributors_length = 0;
|
||||
for (const contributor of node.contributors) {
|
||||
contributors_length = contributors_length + contributor.locked_contributions.length;
|
||||
}
|
||||
|
||||
minContributionAtomicUnits = openContributionRemaining /
|
||||
(MAX_NUMBER_OF_CONTRIBUTORS - contributors_length);
|
||||
}
|
||||
|
||||
const minContributionOxen = minContributionAtomicUnits / 1e9;
|
||||
// ceiling to 4 decimal places
|
||||
return minContributionOxen.toFixed(4);
|
||||
},
|
||||
openForContribution(node, addr = null) {
|
||||
let openContributionRemaining =
|
||||
node.staking_requirement > node.total_reserved
|
||||
? node.staking_requirement - node.total_reserved
|
||||
: 0;
|
||||
if (addr) {
|
||||
openContributionRemaining += this.getUnfilledReservedContribution(node, addr);
|
||||
}
|
||||
return openContributionRemaining;
|
||||
},
|
||||
openForContributionLoki(node) {
|
||||
return (this.openForContribution(node) / 1e9).toFixed(4);
|
||||
openForContributionOxen(node, addr = null) {
|
||||
return (this.openForContribution(node, addr) / 1e9).toFixed(4);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<q-page>
|
||||
<div class="init-screen-page text-center">
|
||||
<div class="absolute-center">
|
||||
<img src="loki.svg" width="400" class="q-mb-md" />
|
||||
<img src="oxen.svg" width="400" class="q-mb-md" />
|
||||
|
||||
<div class="startup-icons q-mt-xl q-mb-lg">
|
||||
<div ref="backend">
|
||||
|
@ -62,10 +62,34 @@
|
|||
d="M7.494,14.958 C3.361,14.958 0,11.622 0,7.52 C0,3.418 3.361,0.082 7.494,0.082 C11.627,0.082 14.989,3.418 14.989,7.52 C14.989,11.622 11.627,14.958 7.494,14.958 L7.494,14.958 Z M7.51,0.938 C3.887,0.938 0.938,3.886 0.938,7.51 C0.938,11.135 3.887,14.083 7.51,14.083 C11.135,14.083 14.083,11.135 14.083,7.51 C14.083,3.886 11.135,0.938 7.51,0.938 L7.51,0.938 Z"
|
||||
class="si-glyph-fill"
|
||||
></path>
|
||||
<rect x="7" y="1" width="0.922" height="14.084" class="si-glyph-fill"></rect>
|
||||
<rect x="0" y="7" width="13.96" height="0.922" class="si-glyph-fill"></rect>
|
||||
<rect x="1" y="4" width="12.406" height="0.906" class="si-glyph-fill"></rect>
|
||||
<rect x="1" y="10" width="12.406" height="0.922" class="si-glyph-fill"></rect>
|
||||
<rect
|
||||
x="7"
|
||||
y="1"
|
||||
width="0.922"
|
||||
height="14.084"
|
||||
class="si-glyph-fill"
|
||||
></rect>
|
||||
<rect
|
||||
x="0"
|
||||
y="7"
|
||||
width="13.96"
|
||||
height="0.922"
|
||||
class="si-glyph-fill"
|
||||
></rect>
|
||||
<rect
|
||||
x="1"
|
||||
y="4"
|
||||
width="12.406"
|
||||
height="0.906"
|
||||
class="si-glyph-fill"
|
||||
></rect>
|
||||
<rect
|
||||
x="1"
|
||||
y="10"
|
||||
width="12.406"
|
||||
height="0.922"
|
||||
class="si-glyph-fill"
|
||||
></rect>
|
||||
<path
|
||||
d="M7.317,14.854 C4.72,13.581 3.043,10.662 3.043,7.417 C3.043,4.247 4.666,1.355 7.181,0.05 L7.642,0.937 C5.455,2.074 4.043,4.617 4.043,7.417 C4.043,10.282 5.502,12.849 7.757,13.955 L7.317,14.854 L7.317,14.854 Z"
|
||||
class="si-glyph-fill"
|
||||
|
@ -112,7 +136,9 @@
|
|||
{{ message }}
|
||||
</div>
|
||||
|
||||
<div v-if="daemonStatus" class="q-mt-xs">{{ $t("strings.syncingDaemon") }}: {{ daemonStatus }}</div>
|
||||
<div v-if="daemonStatus" class="q-mt-xs">
|
||||
{{ $t("strings.syncingDaemon") }}: {{ daemonStatus }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="absolute-bottom">
|
||||
|
@ -144,7 +170,10 @@ export default {
|
|||
if (this.status.code < 3 || !this.isLocalDaemon) return null;
|
||||
|
||||
const currentHeight = this.daemon.info.height_without_bootstrap;
|
||||
const targetHeight = Math.max(this.daemon.info.height, this.daemon.info.target_height);
|
||||
const targetHeight = Math.max(
|
||||
this.daemon.info.height,
|
||||
this.daemon.info.target_height
|
||||
);
|
||||
const percentage = ((100 * currentHeight) / targetHeight).toFixed(1);
|
||||
|
||||
if (targetHeight === 0 || currentHeight >= targetHeight) return null;
|
||||
|
@ -200,7 +229,8 @@ export default {
|
|||
this.$q.notify({
|
||||
type: "warning",
|
||||
timeout: 2000,
|
||||
message: "Warning: " + this.$t("notification.warnings.usingRemoteNode")
|
||||
message:
|
||||
"Warning: " + this.$t("notification.warnings.usingRemoteNode")
|
||||
});
|
||||
break;
|
||||
case 6:
|
||||
|
@ -224,6 +254,9 @@ export default {
|
|||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.message {
|
||||
color: #1f1c47;
|
||||
}
|
||||
.init-screen-page {
|
||||
height: 100vh;
|
||||
position: relative;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<q-page>
|
||||
<div class="init-screen-page text-center">
|
||||
<div class="absolute-center">
|
||||
<img src="loki.svg" width="400" class="q-mb-md" />
|
||||
<img src="oxen.svg" width="400" class="q-mb-md" />
|
||||
|
||||
<div class="q-mt-xl q-mb-lg">
|
||||
<q-spinner color="primary" :size="30" />
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
class="first-step"
|
||||
>
|
||||
<div class="welcome-container">
|
||||
<img src="loki.svg" height="100" class="q-mb-md" />
|
||||
<img src="oxen.svg" height="100" class="q-mb-md" />
|
||||
<div>Wallet Version: v{{ version }}</div>
|
||||
<div>Daemon Version: {{ daemonVersion }}</div>
|
||||
<LanguageSelect class="q-mt-lg" @select="onLanguageSelected" />
|
||||
|
@ -105,7 +105,6 @@ export default {
|
|||
|
||||
.welcome-stepper {
|
||||
height: 100%;
|
||||
// the Loki lighter grey is behind it
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<q-page class="create-wallet">
|
||||
<div class="fields q-mx-md q-mt-md">
|
||||
<LokiField
|
||||
<OxenField
|
||||
:label="$t('fieldLabels.walletName')"
|
||||
:error="$v.wallet.name.$error"
|
||||
>
|
||||
|
@ -14,21 +14,20 @@
|
|||
@keyup.enter="create"
|
||||
@blur="$v.wallet.name.$touch"
|
||||
/>
|
||||
</LokiField>
|
||||
</OxenField>
|
||||
|
||||
<LokiField :label="$t('fieldLabels.seedLanguage')">
|
||||
<OxenField :label="$t('fieldLabels.seedLanguage')">
|
||||
<q-select
|
||||
v-model="wallet.language"
|
||||
:options="languageOptions"
|
||||
:dark="theme == 'dark'"
|
||||
borderless
|
||||
dense
|
||||
emit-value
|
||||
map-options
|
||||
/>
|
||||
</LokiField>
|
||||
</OxenField>
|
||||
|
||||
<LokiField :label="$t('fieldLabels.password')" optional>
|
||||
<OxenField :label="$t('fieldLabels.password')" optional>
|
||||
<q-input
|
||||
v-model="wallet.password"
|
||||
type="password"
|
||||
|
@ -38,9 +37,9 @@
|
|||
dense
|
||||
@keyup.enter="create"
|
||||
/>
|
||||
</LokiField>
|
||||
</OxenField>
|
||||
|
||||
<LokiField :label="$t('fieldLabels.confirmPassword')">
|
||||
<OxenField :label="$t('fieldLabels.confirmPassword')">
|
||||
<q-input
|
||||
v-model="wallet.password_confirm"
|
||||
type="password"
|
||||
|
@ -49,14 +48,34 @@
|
|||
dense
|
||||
@keyup.enter="create"
|
||||
/>
|
||||
</LokiField>
|
||||
</OxenField>
|
||||
|
||||
<q-btn
|
||||
class="submit-button"
|
||||
color="primary"
|
||||
:label="$t('buttons.createWallet')"
|
||||
@click="create"
|
||||
/>
|
||||
<q-field class="q-pb-sm">
|
||||
<q-checkbox
|
||||
v-model="wallet.hardware_wallet"
|
||||
:label="$t('strings.hardwareWallet')"
|
||||
/>
|
||||
</q-field>
|
||||
|
||||
<OxenField
|
||||
v-if="!wallet.hardware_wallet"
|
||||
:label="$t('fieldLabels.seedLanguage')"
|
||||
>
|
||||
<q-select
|
||||
v-model="wallet.language"
|
||||
:options="languageOptions"
|
||||
:dark="theme == 'dark'"
|
||||
hide-underline
|
||||
/>
|
||||
</OxenField>
|
||||
|
||||
<q-field>
|
||||
<q-btn
|
||||
color="primary"
|
||||
:label="$t('buttons.createWallet')"
|
||||
@click="create"
|
||||
/>
|
||||
</q-field>
|
||||
</div>
|
||||
</q-page>
|
||||
</template>
|
||||
|
@ -64,10 +83,10 @@
|
|||
<script>
|
||||
import { required } from "vuelidate/lib/validators";
|
||||
import { mapState } from "vuex";
|
||||
import LokiField from "components/loki_field";
|
||||
import OxenField from "components/oxen_field";
|
||||
export default {
|
||||
components: {
|
||||
LokiField
|
||||
OxenField
|
||||
},
|
||||
data() {
|
||||
const languageOptions = [
|
||||
|
@ -89,7 +108,8 @@ export default {
|
|||
name: "",
|
||||
language: languageOptions[0].value,
|
||||
password: "",
|
||||
password_confirm: ""
|
||||
password_confirm: "",
|
||||
hardware_wallet: false
|
||||
},
|
||||
languageOptions
|
||||
};
|
||||
|
@ -167,11 +187,9 @@ export default {
|
|||
},
|
||||
cancel: {
|
||||
flat: true,
|
||||
label: this.$t("dialog.buttons.cancel"),
|
||||
color: this.theme === "dark" ? "white" : "dark"
|
||||
label: this.$t("dialog.buttons.cancel")
|
||||
},
|
||||
dark: this.theme == "dark",
|
||||
color: "positive"
|
||||
color: "primary"
|
||||
});
|
||||
passwordPromise
|
||||
.onOk(() => {
|
||||
|
|
|
@ -7,8 +7,18 @@
|
|||
{{ info.address }}
|
||||
</div>
|
||||
<div class="q-item-side">
|
||||
<q-btn color="primary" padding="xs" size="sm" icon="file_copy" @click="copyAddress">
|
||||
<q-tooltip anchor="center left" self="center right" :offset="[5, 10]">
|
||||
<q-btn
|
||||
color="primary"
|
||||
padding="xs"
|
||||
size="sm"
|
||||
icon="file_copy"
|
||||
@click="copyAddress"
|
||||
>
|
||||
<q-tooltip
|
||||
anchor="center left"
|
||||
self="center right"
|
||||
:offset="[5, 10]"
|
||||
>
|
||||
{{ $t("menuItems.copyAddress") }}
|
||||
</q-tooltip>
|
||||
</q-btn>
|
||||
|
@ -37,7 +47,10 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<q-expansion-item label="Advanced" header-class="q-mt-sm non-selectable row reverse advanced-options-label">
|
||||
<q-expansion-item
|
||||
label="Advanced"
|
||||
header-class="q-mt-sm non-selectable row reverse advanced-options-label"
|
||||
>
|
||||
<template v-if="secret.view_key != secret.spend_key">
|
||||
<h6 class="q-mb-xs title">{{ $t("strings.viewKey") }}</h6>
|
||||
<div class="row">
|
||||
|
@ -45,8 +58,18 @@
|
|||
{{ secret.view_key }}
|
||||
</div>
|
||||
<div class="q-item-side">
|
||||
<q-btn color="primary" padding="xs" size="sm" icon="file_copy" @click="copyPrivateKey('view_key', $event)">
|
||||
<q-tooltip anchor="center left" self="center right" :offset="[5, 10]">
|
||||
<q-btn
|
||||
color="primary"
|
||||
padding="xs"
|
||||
size="sm"
|
||||
icon="file_copy"
|
||||
@click="copyPrivateKey('view_key', $event)"
|
||||
>
|
||||
<q-tooltip
|
||||
anchor="center left"
|
||||
self="center right"
|
||||
:offset="[5, 10]"
|
||||
>
|
||||
{{ $t("menuItems.copyViewKey") }}
|
||||
</q-tooltip>
|
||||
</q-btn>
|
||||
|
@ -61,8 +84,18 @@
|
|||
{{ secret.spend_key }}
|
||||
</div>
|
||||
<div class="q-item-side">
|
||||
<q-btn color="primary" padding="xs" size="sm" icon="file_copy" @click="copyPrivateKey('spend_key', $event)">
|
||||
<q-tooltip anchor="center left" self="center right" :offset="[5, 10]">
|
||||
<q-btn
|
||||
color="primary"
|
||||
padding="xs"
|
||||
size="sm"
|
||||
icon="file_copy"
|
||||
@click="copyPrivateKey('spend_key', $event)"
|
||||
>
|
||||
<q-tooltip
|
||||
anchor="center left"
|
||||
self="center right"
|
||||
:offset="[5, 10]"
|
||||
>
|
||||
{{ $t("menuItems.copySpendKey") }}
|
||||
</q-tooltip>
|
||||
</q-btn>
|
||||
|
@ -71,7 +104,12 @@
|
|||
</template>
|
||||
</q-expansion-item>
|
||||
|
||||
<q-btn class="q-mt-lg" color="primary" :label="$t('buttons.openWallet')" @click="open" />
|
||||
<q-btn
|
||||
class="q-mt-lg"
|
||||
color="primary"
|
||||
:label="$t('buttons.openWallet')"
|
||||
@click="open"
|
||||
/>
|
||||
</q-page>
|
||||
</template>
|
||||
|
||||
|
@ -137,9 +175,7 @@ export default {
|
|||
ok: {
|
||||
label: this.$t("dialog.buttons.ok"),
|
||||
color: "primary"
|
||||
},
|
||||
color: this.theme === "dark" ? "white" : "dark",
|
||||
dark: this.theme === "dark"
|
||||
}
|
||||
})
|
||||
.onDismiss(() => null)
|
||||
.onCancel(() => null)
|
||||
|
@ -166,45 +202,4 @@ export default {
|
|||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.created {
|
||||
.wallet h6 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.address {
|
||||
text-align: center;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.seed-box {
|
||||
border: 1px solid white;
|
||||
border-radius: 3px;
|
||||
margin: 16px;
|
||||
padding: 16px;
|
||||
|
||||
div,
|
||||
h6 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.seed {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.warning {
|
||||
color: goldenrod;
|
||||
}
|
||||
}
|
||||
h6 {
|
||||
font-size: 18px;
|
||||
margin: 8px 0;
|
||||
font-weight: 450;
|
||||
}
|
||||
.advanced-options-label {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style lang="scss"></style>
|
||||
|
|
|
@ -2,13 +2,20 @@
|
|||
<q-page>
|
||||
<div class="q-mx-md import-old-gui">
|
||||
<q-list link dark no-border class="wallet-list">
|
||||
<q-item v-for="state in directory_state" :key="state.directory" :class="{ selected: state.selected }">
|
||||
<q-item
|
||||
v-for="state in directory_state"
|
||||
:key="state.directory"
|
||||
:class="{ selected: state.selected }"
|
||||
>
|
||||
<q-item-section>
|
||||
<div class="row items-center">
|
||||
<q-item-label class="items-center">
|
||||
<q-checkbox v-model="state.selected" dark color="dark" />
|
||||
</q-item-label>
|
||||
<q-item-label class="wallet-name" @click.native="state.selected = !state.selected">
|
||||
<q-item-label
|
||||
class="wallet-name"
|
||||
@click.native="state.selected = !state.selected"
|
||||
>
|
||||
{{ state.directory }}
|
||||
</q-item-label>
|
||||
</div>
|
||||
|
@ -19,7 +26,7 @@
|
|||
v-model="state.type"
|
||||
hide-underline
|
||||
dark
|
||||
class="q-ma-none full-width"
|
||||
class="q-ma-none full-width nettype-select"
|
||||
:options="selectOptions"
|
||||
emit-value
|
||||
map-options
|
||||
|
@ -93,7 +100,9 @@ export default {
|
|||
this.$q.notify({
|
||||
type: "negative",
|
||||
timeout: 3000,
|
||||
message: this.$t("notification.errors.failedWalletImport") + `: ${wallet}`
|
||||
message:
|
||||
this.$t("notification.errors.failedWalletImport") +
|
||||
`: ${wallet}`
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -109,7 +118,9 @@ export default {
|
|||
methods: {
|
||||
populate_state() {
|
||||
// Keep any directories that intersect
|
||||
const new_state = this.directory_state.filter(state => this.directories.includes(state.directory));
|
||||
const new_state = this.directory_state.filter(state =>
|
||||
this.directories.includes(state.directory)
|
||||
);
|
||||
|
||||
// Add in new directories
|
||||
this.directories
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
<template>
|
||||
<q-page>
|
||||
<div class="q-mx-md import-wallet">
|
||||
<LokiField :label="$t('fieldLabels.newWalletName')" :error="$v.wallet.name.$error">
|
||||
<OxenField
|
||||
:label="$t('fieldLabels.newWalletName')"
|
||||
:error="$v.wallet.name.$error"
|
||||
>
|
||||
<q-input
|
||||
v-model="wallet.name"
|
||||
:placeholder="$t('placeholders.walletName')"
|
||||
|
@ -11,9 +14,13 @@
|
|||
@keyup.enter="import_wallet"
|
||||
@blur="$v.wallet.name.$touch"
|
||||
/>
|
||||
</LokiField>
|
||||
</OxenField>
|
||||
|
||||
<LokiField :label="$t('fieldLabels.walletFile')" disable-hover :error="$v.wallet.path.$error">
|
||||
<OxenField
|
||||
:label="$t('fieldLabels.walletFile')"
|
||||
disable-hover
|
||||
:error="$v.wallet.path.$error"
|
||||
>
|
||||
<q-input
|
||||
v-model="wallet.path"
|
||||
:placeholder="$t('placeholders.selectAFile')"
|
||||
|
@ -22,16 +29,22 @@
|
|||
borderless
|
||||
dense
|
||||
/>
|
||||
<input id="walletPath" ref="fileInput" type="file" hidden @change="setWalletPath" />
|
||||
<input
|
||||
id="walletPath"
|
||||
ref="fileInput"
|
||||
type="file"
|
||||
hidden
|
||||
@change="setWalletPath"
|
||||
/>
|
||||
<q-btn
|
||||
color="secondary"
|
||||
color="primary"
|
||||
:label="$t('buttons.selectWalletFile')"
|
||||
:text-color="theme == 'dark' ? 'white' : 'dark'"
|
||||
@click="selectFile"
|
||||
/>
|
||||
</LokiField>
|
||||
</OxenField>
|
||||
|
||||
<LokiField :label="$t('fieldLabels.password')">
|
||||
<OxenField :label="$t('fieldLabels.password')">
|
||||
<q-input
|
||||
v-model="wallet.password"
|
||||
:placeholder="$t('placeholders.walletPassword')"
|
||||
|
@ -41,9 +54,9 @@
|
|||
dense
|
||||
@keyup.enter="import_wallet"
|
||||
/>
|
||||
</LokiField>
|
||||
</OxenField>
|
||||
|
||||
<LokiField :label="$t('fieldLabels.confirmPassword')">
|
||||
<OxenField :label="$t('fieldLabels.confirmPassword')">
|
||||
<q-input
|
||||
v-model="wallet.password_confirm"
|
||||
type="password"
|
||||
|
@ -52,8 +65,13 @@
|
|||
dense
|
||||
@keyup.enter="import_wallet"
|
||||
/>
|
||||
</LokiField>
|
||||
<q-btn class="submit-button" color="primary" :label="$tc('buttons.importWallet', 1)" @click="import_wallet" />
|
||||
</OxenField>
|
||||
<q-btn
|
||||
class="submit-button"
|
||||
color="primary"
|
||||
:label="$tc('buttons.importWallet', 1)"
|
||||
@click="import_wallet"
|
||||
/>
|
||||
</div>
|
||||
</q-page>
|
||||
</template>
|
||||
|
@ -61,10 +79,10 @@
|
|||
<script>
|
||||
import { required } from "vuelidate/lib/validators";
|
||||
import { mapState } from "vuex";
|
||||
import LokiField from "components/loki_field";
|
||||
import OxenField from "components/oxen_field";
|
||||
export default {
|
||||
components: {
|
||||
LokiField
|
||||
OxenField
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -172,7 +190,7 @@ export default {
|
|||
}
|
||||
}
|
||||
|
||||
.loki-field {
|
||||
.oxen-field {
|
||||
margin-top: 16px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,26 @@
|
|||
<template>
|
||||
<q-page>
|
||||
<q-list class="wallet-list" no-border :dark="theme == 'dark'">
|
||||
<template v-if="wallets.list.length">
|
||||
<q-list class="wallet-list" link no-border :dark="theme == 'dark'">
|
||||
<template v-if="wallet_list.length">
|
||||
<div class="header row justify-between items-center">
|
||||
<div class="header-title">
|
||||
{{ $t("titles.yourWallets") }}
|
||||
</div>
|
||||
<q-btn v-if="wallets.list.length" class="add" icon="add" size="md" color="primary">
|
||||
<q-btn
|
||||
v-if="wallets.list.length"
|
||||
class="add"
|
||||
icon="add"
|
||||
size="md"
|
||||
color="primary"
|
||||
>
|
||||
<q-menu class="header-popover" :content-class="'header-popover'">
|
||||
<q-list separator>
|
||||
<q-item v-for="action in actions" :key="action.name" clickable @click.native="action.handler">
|
||||
<q-item
|
||||
v-for="action in actions"
|
||||
:key="action.name"
|
||||
clickable
|
||||
@click.native="action.handler"
|
||||
>
|
||||
<q-item-section>
|
||||
{{ action.name }}
|
||||
</q-item-section>
|
||||
|
@ -19,55 +30,43 @@
|
|||
</q-btn>
|
||||
</div>
|
||||
<div class="hr-separator" />
|
||||
<q-item
|
||||
v-for="wallet in wallets.list"
|
||||
<!-- Hardware wallets -->
|
||||
<q-list-header v-if="hardware_wallets.length">
|
||||
<div class="header row justify-between items-center">
|
||||
<div class="header-title">
|
||||
{{ $t("strings.hardwareWallets") }}
|
||||
</div>
|
||||
</div>
|
||||
</q-list-header>
|
||||
<WalletListItem
|
||||
v-for="wallet in hardware_wallets"
|
||||
:key="`${wallet.address}-${wallet.name}`"
|
||||
@click.native="openWallet(wallet)"
|
||||
>
|
||||
<q-item-section avatar>
|
||||
<q-icon class="wallet-icon">
|
||||
<svg
|
||||
width="48"
|
||||
viewBox="0 0 17 16"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
class="si-glyph si-glyph-wallet"
|
||||
>
|
||||
<defs class="si-glyph-fill"></defs>
|
||||
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g transform="translate(1.000000, 0.000000)" fill="#434343">
|
||||
<path
|
||||
d="M7.988,10.635 L7.988,8.327 C7.988,7.578 8.561,6.969 9.267,6.969 L13.964,6.969 L13.964,5.531 C13.964,4.849 13.56,4.279 13.007,4.093 L13.007,4.094 L11.356,4.08 L11.336,4.022 L3.925,4.022 L3.784,4.07 L1.17,4.068 L1.165,4.047 C0.529,4.167 0.017,4.743 0.017,5.484 L0.017,13.437 C0.017,14.269 0.665,14.992 1.408,14.992 L12.622,14.992 C13.365,14.992 13.965,14.316 13.965,13.484 L13.965,12.031 L9.268,12.031 C8.562,12.031 7.988,11.384 7.988,10.635 L7.988,10.635 Z"
|
||||
class="si-glyph-fill"
|
||||
></path>
|
||||
<path
|
||||
d="M14.996,8.061 L14.947,8.061 L9.989,8.061 C9.46,8.061 9.031,8.529 9.031,9.106 L9.031,9.922 C9.031,10.498 9.46,10.966 9.989,10.966 L14.947,10.966 L14.996,10.966 C15.525,10.966 15.955,10.498 15.955,9.922 L15.955,9.106 C15.955,8.528 15.525,8.061 14.996,8.061 L14.996,8.061 Z M12.031,10.016 L9.969,10.016 L9.969,9 L12.031,9 L12.031,10.016 L12.031,10.016 Z"
|
||||
class="si-glyph-fill"
|
||||
></path>
|
||||
<path
|
||||
d="M3.926,4.022 L10.557,1.753 L11.337,4.022 L12.622,4.022 C12.757,4.022 12.885,4.051 13.008,4.092 L11.619,0.051 L1.049,3.572 L1.166,4.048 C1.245,4.033 1.326,4.023 1.408,4.023 L3.926,4.023 L3.926,4.022 Z"
|
||||
class="si-glyph-fill"
|
||||
></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</q-icon>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-item-label class="wallet-name" caption>{{ wallet.name }}</q-item-label>
|
||||
<q-item-label class="monospace ellipsis" caption>{{ wallet.address }}</q-item-label>
|
||||
</q-item-section>
|
||||
<ContextMenu
|
||||
:menu-items="menuItems"
|
||||
@openWallet="openWallet(wallet)"
|
||||
@copyAddress="copyAddress(wallet.address)"
|
||||
/>
|
||||
</q-item>
|
||||
<q-separator />
|
||||
:wallet="wallet"
|
||||
:open-wallet="openWallet"
|
||||
/>
|
||||
<!-- Regular wallets -->
|
||||
<q-list-header v-if="hardware_wallets.length">
|
||||
<div class="header row justify-between items-center">
|
||||
<div class="header-title">
|
||||
{{ $t("strings.regularWallets") }}
|
||||
</div>
|
||||
</div>
|
||||
</q-list-header>
|
||||
<WalletListItem
|
||||
v-for="wallet in regular_wallets"
|
||||
:key="`${wallet.address}-${wallet.name}`"
|
||||
:wallet="wallet"
|
||||
:open-wallet="openWallet"
|
||||
/>
|
||||
|
||||
<q-item-separator />
|
||||
</template>
|
||||
<template v-else>
|
||||
<q-item v-for="action in actions" :key="action.name" @click.native="action.handler">
|
||||
<q-item
|
||||
v-for="action in actions"
|
||||
:key="action.name"
|
||||
@click.native="action.handler"
|
||||
>
|
||||
<q-item-section>
|
||||
{{ action.name }}
|
||||
</q-item-section>
|
||||
|
@ -78,27 +77,24 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
const { clipboard } = require("electron");
|
||||
import { mapState } from "vuex";
|
||||
import ContextMenu from "components/menus/contextmenu";
|
||||
import WalletListItem from "components/wallet_list_item";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ContextMenu
|
||||
},
|
||||
data() {
|
||||
const menuItems = [
|
||||
{ action: "openWallet", i18n: "menuItems.openWallet" },
|
||||
{ action: "copyAddress", i18n: "menuItems.copyAddress" }
|
||||
];
|
||||
return {
|
||||
menuItems
|
||||
};
|
||||
WalletListItem
|
||||
},
|
||||
computed: mapState({
|
||||
theme: state => state.gateway.app.config.appearance.theme,
|
||||
wallets: state => state.gateway.wallets,
|
||||
wallet_list: state => state.gateway.wallets.list,
|
||||
status: state => state.gateway.wallet.status,
|
||||
hardware_wallets() {
|
||||
return this.wallet_list.filter(w => w.hardware_wallet);
|
||||
},
|
||||
regular_wallets() {
|
||||
return this.wallet_list.filter(w => !w.hardware_wallet);
|
||||
},
|
||||
actions() {
|
||||
// TODO: Add this in once LOKI has the functionality
|
||||
// <q-item @click.native="restoreViewWallet()">
|
||||
|
@ -173,15 +169,15 @@ export default {
|
|||
type: "password"
|
||||
},
|
||||
ok: {
|
||||
label: this.$t("dialog.buttons.open")
|
||||
label: this.$t("dialog.buttons.open"),
|
||||
color: "primary"
|
||||
},
|
||||
cancel: {
|
||||
flat: true,
|
||||
label: this.$t("dialog.buttons.cancel"),
|
||||
color: this.theme == "dark" ? "white" : "dark"
|
||||
label: this.$t("dialog.buttons.cancel")
|
||||
},
|
||||
dark: this.theme == "dark",
|
||||
color: "positive"
|
||||
color: "#1F1C47",
|
||||
persistent: true
|
||||
})
|
||||
.onOk(password => {
|
||||
this.$q.loading.show({
|
||||
|
@ -221,14 +217,6 @@ export default {
|
|||
},
|
||||
importLegacyWallet() {
|
||||
this.$router.replace({ path: "wallet-select/import-legacy" });
|
||||
},
|
||||
copyAddress(address) {
|
||||
clipboard.writeText(address);
|
||||
this.$q.notify({
|
||||
type: "positive",
|
||||
timeout: 1000,
|
||||
message: this.$t("notification.positive.addressCopied")
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<q-page>
|
||||
<div class="q-mx-md">
|
||||
<LokiField
|
||||
<OxenField
|
||||
class="q-mt-md"
|
||||
:label="$t('fieldLabels.walletName')"
|
||||
:error="$v.wallet.name.$error"
|
||||
|
@ -9,34 +9,32 @@
|
|||
<q-input
|
||||
v-model="wallet.name"
|
||||
:placeholder="$t('placeholders.walletName')"
|
||||
:dark="theme == 'dark'"
|
||||
borderless
|
||||
dense
|
||||
@keyup.enter="restore_wallet"
|
||||
@blur="$v.wallet.name.$touch"
|
||||
/>
|
||||
</LokiField>
|
||||
</OxenField>
|
||||
|
||||
<LokiField
|
||||
<OxenField
|
||||
class="q-mt-md"
|
||||
:label="$t('fieldLabels.mnemonicSeed')"
|
||||
:error="$v.wallet.seed.$error"
|
||||
>
|
||||
<q-input
|
||||
v-model="wallet.seed"
|
||||
class="full-width text-area-loki"
|
||||
class="full-width text-area-oxen"
|
||||
:placeholder="$t('placeholders.mnemonicSeed')"
|
||||
type="textarea"
|
||||
:dark="theme == 'dark'"
|
||||
borderless
|
||||
dense
|
||||
@blur="$v.wallet.seed.$touch"
|
||||
/>
|
||||
</LokiField>
|
||||
</OxenField>
|
||||
|
||||
<div class="row items-end q-mt-md">
|
||||
<div class="col-md-9 col-sm-8">
|
||||
<LokiField
|
||||
<OxenField
|
||||
v-if="wallet.refresh_type == 'date'"
|
||||
:label="$t('fieldLabels.restoreFromDate')"
|
||||
>
|
||||
|
@ -59,7 +57,6 @@
|
|||
>
|
||||
<q-date
|
||||
v-model="wallet.refresh_start_date"
|
||||
:dark="theme == 'dark'"
|
||||
:options="dateRangeOptions"
|
||||
>
|
||||
<div class="row items-center justify-end">
|
||||
|
@ -75,8 +72,8 @@
|
|||
</q-icon>
|
||||
</template>
|
||||
</q-input>
|
||||
</LokiField>
|
||||
<LokiField
|
||||
</OxenField>
|
||||
<OxenField
|
||||
v-else-if="wallet.refresh_type == 'height'"
|
||||
:label="$t('fieldLabels.restoreFromBlockHeight')"
|
||||
:error="$v.wallet.refresh_start_height.$error"
|
||||
|
@ -90,13 +87,12 @@
|
|||
dense
|
||||
@blur="$v.wallet.refresh_start_height.$touch"
|
||||
/>
|
||||
</LokiField>
|
||||
</OxenField>
|
||||
</div>
|
||||
<div class="col-sm-4 col-md-3">
|
||||
<template v-if="wallet.refresh_type == 'date'">
|
||||
<q-btn
|
||||
class="restore-from-button"
|
||||
:text-color="theme == 'dark' ? 'white' : 'dark'"
|
||||
flat
|
||||
@click="wallet.refresh_type = 'height'"
|
||||
>
|
||||
|
@ -109,7 +105,6 @@
|
|||
<template v-else-if="wallet.refresh_type == 'height'">
|
||||
<q-btn
|
||||
class="restore-from-button"
|
||||
:text-color="theme == 'dark' ? 'white' : 'dark'"
|
||||
flat
|
||||
@click="wallet.refresh_type = 'date'"
|
||||
>
|
||||
|
@ -122,7 +117,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<LokiField class="q-mt-md" :label="$t('fieldLabels.password')">
|
||||
<OxenField class="q-mt-md" :label="$t('fieldLabels.password')">
|
||||
<q-input
|
||||
v-model="wallet.password"
|
||||
:placeholder="$t('placeholders.walletPassword')"
|
||||
|
@ -132,9 +127,9 @@
|
|||
dense
|
||||
@keyup.enter="restore_wallet"
|
||||
/>
|
||||
</LokiField>
|
||||
</OxenField>
|
||||
|
||||
<LokiField class="q-mt-md" :label="$t('fieldLabels.confirmPassword')">
|
||||
<OxenField class="q-mt-md" :label="$t('fieldLabels.confirmPassword')">
|
||||
<q-input
|
||||
v-model="wallet.password_confirm"
|
||||
type="password"
|
||||
|
@ -143,7 +138,7 @@
|
|||
dense
|
||||
@keyup.enter="restore_wallet"
|
||||
/>
|
||||
</LokiField>
|
||||
</OxenField>
|
||||
<q-btn
|
||||
class="submit-button"
|
||||
color="primary"
|
||||
|
@ -157,7 +152,7 @@
|
|||
<script>
|
||||
import { required, numeric } from "vuelidate/lib/validators";
|
||||
import { mapState } from "vuex";
|
||||
import LokiField from "components/loki_field";
|
||||
import OxenField from "components/oxen_field";
|
||||
import { date } from "quasar";
|
||||
import _ from "lodash";
|
||||
|
||||
|
@ -167,7 +162,7 @@ let dateFirstBlock = date.formatDate(timeStampFirstBlock, qDateFormat);
|
|||
|
||||
export default {
|
||||
components: {
|
||||
LokiField
|
||||
OxenField
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
</div>
|
||||
|
||||
<template v-if="address_book_combined.length">
|
||||
<q-list link no-border :dark="theme == 'dark'" class="loki-list">
|
||||
<q-list link no-border :dark="theme == 'dark'" class="oxen-list">
|
||||
<q-item
|
||||
v-for="(entry, index) in address_book_combined"
|
||||
:key="`${entry.address}-${entry.name}-${index}`"
|
||||
class="loki-list-item"
|
||||
class="oxen-list-item"
|
||||
@click.native="details(entry)"
|
||||
>
|
||||
<q-item-section>
|
||||
|
@ -27,7 +27,7 @@
|
|||
:name="entry.starred ? 'star' : 'star_border'"
|
||||
/>
|
||||
<q-btn
|
||||
color="secondary"
|
||||
color="primary"
|
||||
style="margin-left: 10px;"
|
||||
:label="$t('buttons.send')"
|
||||
:disabled="view_only"
|
||||
|
@ -45,7 +45,7 @@
|
|||
</q-list>
|
||||
</template>
|
||||
<template v-else>
|
||||
<p class="q-ma-md">{{ $t("strings.addressBookIsEmpty") }}</p>
|
||||
<p class="q-ma-md tab-desc">{{ $t("strings.addressBookIsEmpty") }}</p>
|
||||
</template>
|
||||
|
||||
<q-page-sticky position="bottom-right" :offset="[18, 18]">
|
||||
|
@ -126,9 +126,10 @@ export default {
|
|||
.header {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #1f1c47;
|
||||
}
|
||||
|
||||
.loki-list-item {
|
||||
.oxen-list-item {
|
||||
cursor: pointer;
|
||||
padding-top: 12px;
|
||||
padding-bottom: 12px;
|
||||
|
|
|
@ -4,28 +4,36 @@
|
|||
<q-btn-toggle
|
||||
v-model="screen"
|
||||
toggle-color="primary"
|
||||
color="secondary"
|
||||
color="accent"
|
||||
:options="[
|
||||
{ label: $t('titles.advanced.prove'), value: 'prove' },
|
||||
{
|
||||
label: $t('titles.advanced.checkTransaction'),
|
||||
value: 'check'
|
||||
},
|
||||
{
|
||||
label: $t('titles.advanced.signAndVerify'),
|
||||
value: 'signAndVerify'
|
||||
}
|
||||
]"
|
||||
/>
|
||||
</div>
|
||||
<ProveTransaction v-if="screen === 'prove'" />
|
||||
<CheckTransaction v-if="screen === 'check'" />
|
||||
<SignAndVerify v-if="screen === 'signAndVerify'" />
|
||||
</q-page>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ProveTransaction from "components/prove_transaction";
|
||||
import CheckTransaction from "components/check_transaction";
|
||||
import ProveTransaction from "components/advanced/prove_transaction";
|
||||
import CheckTransaction from "components/advanced/check_transaction";
|
||||
import SignAndVerify from "components/advanced/sign_and_verify";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ProveTransaction,
|
||||
CheckTransaction
|
||||
CheckTransaction,
|
||||
SignAndVerify
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
|
@ -1,37 +1,37 @@
|
|||
<template>
|
||||
<q-page class="lns-page">
|
||||
<q-page class="ons-page">
|
||||
<div class="header row items-center justify-center q-pt-md">
|
||||
<q-btn-toggle
|
||||
v-model="screen"
|
||||
toggle-color="primary"
|
||||
color="secondary"
|
||||
color="accent"
|
||||
:options="[
|
||||
{
|
||||
label: $t('titles.lns.purchase'),
|
||||
label: $t('titles.ons.purchase'),
|
||||
value: 'purchase'
|
||||
},
|
||||
{
|
||||
label: $t('titles.lns.myLns'),
|
||||
value: 'my_lns'
|
||||
label: $t('titles.ons.myOns'),
|
||||
value: 'my_ons'
|
||||
}
|
||||
]"
|
||||
/>
|
||||
</div>
|
||||
<LNSPurchase v-if="screen === 'purchase'" ref="purchase" />
|
||||
<MyLNS v-if="screen === 'my_lns'" @onUpdate="onUpdate" @onRenew="onRenew" />
|
||||
<ONSPurchase v-if="screen === 'purchase'" ref="purchase" />
|
||||
<MyONS v-if="screen === 'my_ons'" @onUpdate="onUpdate" @onRenew="onRenew" />
|
||||
</q-page>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import LNSPurchase from "components/lns/lns_purchase";
|
||||
import MyLNS from "components/lns/lns_mylns";
|
||||
import ONSPurchase from "components/ons/ons_purchase";
|
||||
import MyONS from "components/ons/ons_myons";
|
||||
import Vue from "vue";
|
||||
import _ from "lodash";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MyLNS,
|
||||
LNSPurchase
|
||||
MyONS,
|
||||
ONSPurchase
|
||||
},
|
||||
data() {
|
||||
return {
|
|
@ -1,7 +1,9 @@
|
|||
<template>
|
||||
<q-page class="receive">
|
||||
<q-list link no-border :dark="theme == 'dark'" class="loki-list">
|
||||
<q-item-label header>{{ $t("strings.addresses.myPrimaryAddress") }}</q-item-label>
|
||||
<q-list link no-border :dark="theme == 'dark'" class="oxen-list">
|
||||
<q-item-label header class="list-header">{{
|
||||
$t("strings.addresses.myPrimaryAddress")
|
||||
}}</q-item-label>
|
||||
<ReceiveItem
|
||||
v-for="address in address_list.primary"
|
||||
:key="address.address"
|
||||
|
@ -15,15 +17,20 @@
|
|||
/>
|
||||
|
||||
<template v-if="address_list.used.length">
|
||||
<q-item-label header>{{ $t("strings.addresses.myUsedAddresses") }}</q-item-label>
|
||||
<q-item-label header class="list-header">{{
|
||||
$t("strings.addresses.myUsedAddresses")
|
||||
}}</q-item-label>
|
||||
<ReceiveItem
|
||||
v-for="address in address_list.used"
|
||||
:key="address.address"
|
||||
:address="address"
|
||||
:sublabel="
|
||||
`${$t('strings.addresses.subAddress')} (${$t('strings.addresses.subAddressIndex', {
|
||||
index: address.address_index
|
||||
})})`
|
||||
`${$t('strings.addresses.subAddress')} (${$t(
|
||||
'strings.addresses.subAddressIndex',
|
||||
{
|
||||
index: address.address_index
|
||||
}
|
||||
)})`
|
||||
"
|
||||
:show-q-r="showQR"
|
||||
:copy-address="copyAddress"
|
||||
|
@ -32,15 +39,20 @@
|
|||
</template>
|
||||
|
||||
<template v-if="address_list.unused.length">
|
||||
<q-item-label header>{{ $t("strings.addresses.myUnusedAddresses") }}</q-item-label>
|
||||
<q-item-label header class="list-header">{{
|
||||
$t("strings.addresses.myUnusedAddresses")
|
||||
}}</q-item-label>
|
||||
<ReceiveItem
|
||||
v-for="address in address_list.unused"
|
||||
:key="address.address"
|
||||
:address="address"
|
||||
:sublabel="
|
||||
`${$t('strings.addresses.subAddress')} (${$t('strings.addresses.subAddressIndex', {
|
||||
index: address.address_index
|
||||
})})`
|
||||
`${$t('strings.addresses.subAddress')} (${$t(
|
||||
'strings.addresses.subAddressIndex',
|
||||
{
|
||||
index: address.address_index
|
||||
}
|
||||
)})`
|
||||
"
|
||||
:show-q-r="showQR"
|
||||
:copy-address="copyAddress"
|
||||
|
@ -57,10 +69,18 @@
|
|||
<q-card class="qr-code-card">
|
||||
<div class="text-center q-mb-sm q-pa-md" style="background: white;">
|
||||
<QrcodeVue ref="qr" :value="QR.address" size="240"> </QrcodeVue>
|
||||
<ContextMenu :menu-items="menuItems" @copyQR="copyQR()" @saveQR="saveQR()" />
|
||||
<ContextMenu
|
||||
:menu-items="menuItems"
|
||||
@copyQR="copyQR()"
|
||||
@saveQR="saveQR()"
|
||||
/>
|
||||
</div>
|
||||
<q-card-actions>
|
||||
<q-btn color="primary" :label="$t('buttons.close')" @click="QR.visible = false" />
|
||||
<q-btn
|
||||
color="primary"
|
||||
:label="$t('buttons.close')"
|
||||
@click="QR.visible = false"
|
||||
/>
|
||||
</q-card-actions>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
|
@ -161,7 +181,7 @@ export default {
|
|||
font-weight: 400;
|
||||
}
|
||||
|
||||
.loki-list-item {
|
||||
.oxen-list-item {
|
||||
cursor: pointer;
|
||||
|
||||
.q-item-section {
|
||||
|
|
|
@ -10,13 +10,12 @@
|
|||
<div class="row gutter-md">
|
||||
<!-- Amount -->
|
||||
<div class="col-6 amount">
|
||||
<LokiField
|
||||
<OxenField
|
||||
:label="$t('fieldLabels.amount')"
|
||||
:error="$v.newTx.amount.$error"
|
||||
>
|
||||
<q-input
|
||||
v-model="newTx.amount"
|
||||
:dark="theme == 'dark'"
|
||||
type="number"
|
||||
min="0"
|
||||
:max="unlocked_balance / 1e9"
|
||||
|
@ -26,100 +25,88 @@
|
|||
@blur="$v.newTx.amount.$touch"
|
||||
/>
|
||||
<q-btn
|
||||
color="secondary"
|
||||
:text-color="theme == 'dark' ? 'white' : 'dark'"
|
||||
color="primary"
|
||||
@click="newTx.amount = unlocked_balance / 1e9"
|
||||
>
|
||||
{{ $t("buttons.all") }}
|
||||
</q-btn>
|
||||
</LokiField>
|
||||
</OxenField>
|
||||
</div>
|
||||
|
||||
<!-- Priority -->
|
||||
<div class="col-6 priority">
|
||||
<LokiField :label="$t('fieldLabels.priority')">
|
||||
<OxenField :label="$t('fieldLabels.priority')">
|
||||
<q-select
|
||||
v-model="newTx.priority"
|
||||
emit-value
|
||||
map-options
|
||||
:dark="theme == 'dark'"
|
||||
:options="priorityOptions"
|
||||
borderless
|
||||
dense
|
||||
/>
|
||||
</LokiField>
|
||||
</OxenField>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Address -->
|
||||
<div class="col q-mt-sm">
|
||||
<LokiField
|
||||
<OxenField
|
||||
:label="$t('fieldLabels.address')"
|
||||
:error="$v.newTx.address.$error"
|
||||
>
|
||||
<q-input
|
||||
v-model.trim="newTx.address"
|
||||
:dark="theme == 'dark'"
|
||||
:placeholder="address_placeholder"
|
||||
borderless
|
||||
dense
|
||||
@blur="$v.newTx.address.$touch"
|
||||
/>
|
||||
<q-btn
|
||||
color="secondary"
|
||||
:text-color="theme == 'dark' ? 'white' : 'dark'"
|
||||
to="addressbook"
|
||||
>
|
||||
<q-btn color="primary" to="addressbook">
|
||||
{{ $t("buttons.contacts") }}
|
||||
</q-btn>
|
||||
</LokiField>
|
||||
</OxenField>
|
||||
</div>
|
||||
|
||||
<!-- Notes -->
|
||||
<div class="col q-mt-sm">
|
||||
<LokiField :label="$t('fieldLabels.notes')" optional>
|
||||
<OxenField :label="$t('fieldLabels.notes')" optional>
|
||||
<q-input
|
||||
v-model="newTx.note"
|
||||
class="full-width text-area-loki"
|
||||
class="full-width text-area-oxen"
|
||||
type="textarea"
|
||||
:dark="theme == 'dark'"
|
||||
:placeholder="$t('placeholders.transactionNotes')"
|
||||
borderless
|
||||
dense
|
||||
/>
|
||||
</LokiField>
|
||||
</OxenField>
|
||||
</div>
|
||||
|
||||
<q-checkbox
|
||||
v-model="newTx.address_book.save"
|
||||
:label="$t('strings.saveToAddressBook')"
|
||||
:dark="theme == 'dark'"
|
||||
color="dark"
|
||||
/>
|
||||
<div v-if="newTx.address_book.save">
|
||||
<LokiField :label="$t('fieldLabels.name')" optional>
|
||||
<OxenField :label="$t('fieldLabels.name')" optional>
|
||||
<q-input
|
||||
v-model="newTx.address_book.name"
|
||||
:dark="theme == 'dark'"
|
||||
:placeholder="$t('placeholders.addressBookName')"
|
||||
borderless
|
||||
dense
|
||||
/>
|
||||
</LokiField>
|
||||
<LokiField class="q-mt-sm" :label="$t('fieldLabels.notes')" optional>
|
||||
</OxenField>
|
||||
<OxenField class="q-mt-sm" :label="$t('fieldLabels.notes')" optional>
|
||||
<q-input
|
||||
v-model="newTx.address_book.description"
|
||||
type="textarea"
|
||||
class="full-width text-area-loki"
|
||||
class="full-width text-area-oxen"
|
||||
rows="2"
|
||||
:dark="theme == 'dark'"
|
||||
:placeholder="$t('placeholders.additionalNotes')"
|
||||
borderless
|
||||
dense
|
||||
/>
|
||||
</LokiField>
|
||||
</OxenField>
|
||||
</div>
|
||||
<!-- div required so button below checkbox -->
|
||||
<!-- div required so the button falls below the checkbox -->
|
||||
<div>
|
||||
<q-btn
|
||||
class="send-btn"
|
||||
|
@ -139,7 +126,7 @@
|
|||
:on-confirm-transaction="onConfirmTransaction"
|
||||
:on-cancel-transaction="onCancelTransaction"
|
||||
/>
|
||||
<q-inner-loading :showing="tx_status.sending" :dark="theme == 'dark'">
|
||||
<q-inner-loading :showing="tx_status.sending">
|
||||
<q-spinner color="primary" size="30" />
|
||||
</q-inner-loading>
|
||||
</template>
|
||||
|
@ -150,7 +137,7 @@
|
|||
import { mapState } from "vuex";
|
||||
import { required, decimal } from "vuelidate/lib/validators";
|
||||
import { address, greater_than_zero } from "src/validators/common";
|
||||
import LokiField from "components/loki_field";
|
||||
import OxenField from "components/oxen_field";
|
||||
import WalletPassword from "src/mixins/wallet_password";
|
||||
import ConfirmDialogMixin from "src/mixins/confirm_dialog_mixin";
|
||||
import ConfirmTransactionDialog from "components/confirm_tx_dialog";
|
||||
|
@ -161,7 +148,7 @@ const DO_NOTHING = 10;
|
|||
|
||||
export default {
|
||||
components: {
|
||||
LokiField,
|
||||
OxenField,
|
||||
ConfirmTransactionDialog
|
||||
},
|
||||
mixins: [WalletPassword, ConfirmDialogMixin],
|
||||
|
@ -383,9 +370,7 @@ export default {
|
|||
ok: {
|
||||
label: this.$t("dialog.transfer.ok"),
|
||||
color: "primary"
|
||||
},
|
||||
dark: this.theme == "dark",
|
||||
color: this.theme == "dark" ? "white" : "dark"
|
||||
}
|
||||
});
|
||||
passwordDialog
|
||||
.onOk(password => {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<q-btn-toggle
|
||||
v-model="screen"
|
||||
toggle-color="primary"
|
||||
color="secondary"
|
||||
color="accent"
|
||||
:options="[
|
||||
{
|
||||
label: $t('titles.serviceNode.myStakes'),
|
||||
|
|
|
@ -5,27 +5,25 @@
|
|||
{{ $t("titles.transactions") }}
|
||||
</div>
|
||||
|
||||
<LokiField class="col-5 q-px-sm" :label="$t('fieldLabels.filter')">
|
||||
<OxenField class="col-5 q-px-sm" :label="$t('fieldLabels.filter')">
|
||||
<q-input
|
||||
v-model="tx_filter"
|
||||
:dark="theme == 'dark'"
|
||||
:placeholder="$t('placeholders.filterTx')"
|
||||
borderless
|
||||
dense
|
||||
/>
|
||||
</LokiField>
|
||||
</OxenField>
|
||||
|
||||
<LokiField class="col-2" :label="$t('fieldLabels.filterTransactionType')">
|
||||
<OxenField class="col-2" :label="$t('fieldLabels.filterTransactionType')">
|
||||
<q-select
|
||||
v-model="tx_type"
|
||||
:dark="theme == 'dark'"
|
||||
:options="tx_type_options"
|
||||
borderless
|
||||
dense
|
||||
emit-value
|
||||
map-options
|
||||
/>
|
||||
</LokiField>
|
||||
</OxenField>
|
||||
</div>
|
||||
<TxList :type="tx_type" :filter="tx_filter" />
|
||||
</q-page>
|
||||
|
@ -34,11 +32,11 @@
|
|||
<script>
|
||||
import { mapState } from "vuex";
|
||||
import TxList from "components/tx_list";
|
||||
import LokiField from "components/loki_field";
|
||||
import OxenField from "components/oxen_field";
|
||||
export default {
|
||||
components: {
|
||||
TxList,
|
||||
LokiField
|
||||
OxenField
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
|
@ -94,8 +94,8 @@ export default [
|
|||
component: () => import("pages/wallet/service-node")
|
||||
},
|
||||
{
|
||||
path: "lns",
|
||||
component: () => import("pages/wallet/lns")
|
||||
path: "ons",
|
||||
component: () => import("pages/wallet/ons")
|
||||
},
|
||||
{
|
||||
path: "advanced",
|
||||
|
|
|
@ -10,6 +10,8 @@ export const resetWalletData = state => {
|
|||
height: 0,
|
||||
balance: 0,
|
||||
unlocked_balance: 0,
|
||||
accrued_balance: 0,
|
||||
accrued_balance_next_payout: 0,
|
||||
view_only: false
|
||||
},
|
||||
secret: {
|
||||
|
|
|
@ -39,8 +39,23 @@ export const set_check_transaction_status = (state, data) => {
|
|||
...data
|
||||
};
|
||||
};
|
||||
export const set_lns_status = (state, data) => {
|
||||
state.lns_status = data;
|
||||
|
||||
export const set_sign_status = (state, data) => {
|
||||
state.sign_status = {
|
||||
...state.sign_status,
|
||||
...data
|
||||
};
|
||||
};
|
||||
|
||||
export const set_verify_status = (state, data) => {
|
||||
state.verify_status = {
|
||||
...state.verify_status,
|
||||
...data
|
||||
};
|
||||
};
|
||||
|
||||
export const set_ons_status = (state, data) => {
|
||||
state.ons_status = data;
|
||||
};
|
||||
|
||||
export const set_update_required = (state, data) => {
|
||||
|
|
|
@ -33,7 +33,11 @@ export default {
|
|||
height: 0,
|
||||
balance: 0,
|
||||
unlocked_balance: 0,
|
||||
view_only: false
|
||||
view_only: false,
|
||||
hardware_wallet: false,
|
||||
accrued_balance: 0,
|
||||
accrued_balance_next_payout: 0
|
||||
|
||||
},
|
||||
secret: {
|
||||
mnemonic: "",
|
||||
|
@ -48,7 +52,7 @@ export default {
|
|||
unused: [],
|
||||
address_book: []
|
||||
},
|
||||
lnsRecords: [],
|
||||
onsRecords: [],
|
||||
isRPCSyncing: false
|
||||
},
|
||||
tx_status: {
|
||||
|
@ -96,7 +100,20 @@ export default {
|
|||
i18n: "",
|
||||
state: {}
|
||||
},
|
||||
lns_status: {
|
||||
sign_status: {
|
||||
code: 0,
|
||||
message: "",
|
||||
i18n: "",
|
||||
signature: "",
|
||||
sending: false
|
||||
},
|
||||
verify_status: {
|
||||
code: 0,
|
||||
message: "",
|
||||
i18n: "",
|
||||
sending: false
|
||||
},
|
||||
ons_status: {
|
||||
code: 0,
|
||||
message: "",
|
||||
i18n: "",
|
||||
|
|
|
@ -1945,11 +1945,11 @@ return{_strlen:lb,_ge_mul8:Va,_keccak:db,_ge_scalarmult:Ta,_ge_fromfe_frombytes_
|
|||
|
||||
|
||||
|
||||
var lokiConfig = {
|
||||
var oxenConfig = {
|
||||
coinUnitPlaces: 12,
|
||||
coinSymbol: 'LOKI',
|
||||
coinName: 'Loki',
|
||||
coinUriPrefix: 'loki:',
|
||||
coinSymbol: 'OXEN',
|
||||
coinName: 'Oxen',
|
||||
coinUriPrefix: 'oxen:',
|
||||
addressPrefix: 114,
|
||||
};
|
||||
|
||||
|
@ -2386,7 +2386,7 @@ var cnUtilGen = function(initConfig) {
|
|||
|
||||
return this;
|
||||
};
|
||||
var cnUtil = cnUtilGen(lokiConfig);
|
||||
var cnUtil = cnUtilGen(oxenConfig);
|
||||
/*
|
||||
mnemonic.js : Converts between 4-byte aligned strings and a human-readable
|
||||
sequence of words. Uses 1626 common words taken from wikipedia article:
|
||||
|
|
|
@ -17,7 +17,7 @@ export const session_id = input => {
|
|||
return input.length === 66 && /^05[0-9A-Za-z]+$/.test(input);
|
||||
};
|
||||
|
||||
// shortened Lokinet LNS name
|
||||
// shortened Lokinet ONS name
|
||||
export const lokinet_name = (input, lokiExt = false) => {
|
||||
let inputSafe = input || "";
|
||||
let maxLength = 32;
|
||||
|
|