Compare commits
39 commits
Author | SHA1 | Date | |
---|---|---|---|
fb159c17a0 | |||
f7eb6580cc | |||
43720b34ba | |||
f1f0f002ce | |||
86afa21a60 | |||
0169acba81 | |||
073d950d41 | |||
4eaaebd739 | |||
a9e2106fda | |||
8b427989c5 | |||
f16ce3c69b | |||
a1b3330e5e | |||
3da8f5420b | |||
109e896506 | |||
8ad38f381e | |||
1e32315346 | |||
ef8c645a6a | |||
15ecdf1e57 | |||
587b00c93a | |||
aba2bead27 | |||
85ce58f69c | |||
bb7e00b0eb | |||
d60b35ebef | |||
eb60c52224 | |||
61828ea2db | |||
7e819e14d1 | |||
1d9b7d9698 | |||
82c05588bc | |||
1cddd05bc0 | |||
8ad0d1c461 | |||
a22a75913c | |||
e797da0ed8 | |||
6936c14ed2 | |||
c626ed5a48 | |||
d79d05ef5a | |||
|
094a5b8969 | ||
|
12a75f8370 | ||
|
1c14b9aa93 | ||
|
8ea388554a |
44 changed files with 1892 additions and 1391 deletions
|
@ -109,11 +109,11 @@ jobs:
|
|||
- name: Install cargo-zigbuild
|
||||
run: cargo install cargo-zigbuild
|
||||
- name: Download SDK
|
||||
run: wget https://github.com/phracker/MacOSX-SDKs/releases/download/11.3/MacOSX10.15.sdk.tar.xz
|
||||
run: wget https://github.com/phracker/MacOSX-SDKs/releases/download/11.3/MacOSX11.0.sdk.tar.xz
|
||||
- name: Setup SDK env
|
||||
run: tar xf ${{ github.workspace }}/MacOSX10.15.sdk.tar.xz && echo "SDKROOT=${{ github.workspace }}/MacOSX10.15.sdk" >> $GITHUB_ENV
|
||||
run: tar xf ${{ github.workspace }}/MacOSX11.0.sdk.tar.xz && echo "SDKROOT=${{ github.workspace }}/MacOSX11.0.sdk" >> $GITHUB_ENV
|
||||
- name: Setup platform env
|
||||
run: echo "MACOSX_DEPLOYMENT_TARGET=10.15" >> $GITHUB_ENV
|
||||
run: echo "MACOSX_DEPLOYMENT_TARGET=11.0" >> $GITHUB_ENV
|
||||
- name: Release x86
|
||||
run: |
|
||||
rustup target add x86_64-apple-darwin
|
||||
|
@ -129,12 +129,6 @@ jobs:
|
|||
working-directory: target/x86_64-apple-darwin/release
|
||||
shell: bash
|
||||
run: sha256sum grim-${{ github.ref_name }}-macos-x86_64.zip > grim-${{ github.ref_name }}-macos-x86_64-sha256sum.txt
|
||||
- name: Download SDK
|
||||
run: wget https://github.com/phracker/MacOSX-SDKs/releases/download/11.3/MacOSX11.0.sdk.tar.xz
|
||||
- name: Setup SDK env
|
||||
run: tar xf ${{ github.workspace }}/MacOSX11.0.sdk.tar.xz && echo "SDKROOT=${{ github.workspace }}/MacOSX11.0.sdk" >> $GITHUB_ENV
|
||||
- name: Setup platform env
|
||||
run: echo "MACOSX_DEPLOYMENT_TARGET=11.0" >> $GITHUB_ENV
|
||||
- name: Release ARM
|
||||
run: |
|
||||
rustup target add aarch64-apple-darwin
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -18,4 +18,5 @@ target
|
|||
app/src/main/jniLibs
|
||||
macos/cert.pem
|
||||
linux/Grim.AppDir/AppRun
|
||||
.intentionally-empty-file.o
|
||||
.intentionally-empty-file.o
|
||||
Cargo.toml-e
|
2183
Cargo.lock
generated
2183
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
55
Cargo.toml
55
Cargo.toml
|
@ -1,10 +1,10 @@
|
|||
[package]
|
||||
name = "grim"
|
||||
version = "0.2.2"
|
||||
authors = ["Ardocrat <ardocrat@proton.me>"]
|
||||
version = "0.2.4"
|
||||
authors = ["Ardocrat <ardocrat@gri.mw>"]
|
||||
description = "Cross-platform GUI for Grin with focus on usability and availability to be used by anyone, anywhere."
|
||||
license = "Apache-2.0"
|
||||
repository = "https://github.com/ardocrat/grim"
|
||||
repository = "https://gri.mw/code/GUI/grim"
|
||||
keywords = [ "crypto", "grin", "mimblewimble" ]
|
||||
edition = "2021"
|
||||
|
||||
|
@ -25,10 +25,9 @@ codegen-units = 1
|
|||
panic = "abort"
|
||||
|
||||
[dependencies]
|
||||
log = "0.4.22"
|
||||
log = "0.4.27"
|
||||
|
||||
## node
|
||||
openssl-sys = { version = "0.9.103", features = ["vendored"] }
|
||||
grin_api = "5.3.3"
|
||||
grin_chain = "5.3.3"
|
||||
grin_config = "5.3.3"
|
||||
|
@ -51,12 +50,12 @@ egui_extras = { version = "0.29.1", features = ["image", "svg"] }
|
|||
rust-i18n = "2.3.1"
|
||||
|
||||
## other
|
||||
anyhow = "1.0.89"
|
||||
pin-project = "1.1.6"
|
||||
anyhow = "1.0.97"
|
||||
pin-project = "1.1.10"
|
||||
backtrace = "0.3.74"
|
||||
thiserror = "1.0.64"
|
||||
futures = "0.3.31"
|
||||
dirs = "5.0.1"
|
||||
dirs = "6.0.0"
|
||||
sys-locale = "0.3.1"
|
||||
chrono = "0.4.38"
|
||||
parking_lot = "0.12.3"
|
||||
|
@ -65,11 +64,11 @@ toml = "0.8.19"
|
|||
serde = "1.0.210"
|
||||
local-ip-address = "0.6.3"
|
||||
url = "2.5.2"
|
||||
rand = "0.8.5"
|
||||
serde_derive = "1.0.210"
|
||||
serde_json = "1.0.128"
|
||||
tokio = { version = "1.40.0", features = ["full"] }
|
||||
image = "0.25.2"
|
||||
rand = "0.9.0"
|
||||
serde_derive = "1.0.219"
|
||||
serde_json = "1.0.140"
|
||||
tokio = { version = "1.44.1", features = ["full"] }
|
||||
image = "0.25.6"
|
||||
rqrr = "0.8.0"
|
||||
qrcodegen = "1.8.0"
|
||||
qrcode = "0.14.1"
|
||||
|
@ -78,23 +77,23 @@ gif = "0.13.1"
|
|||
rkv = { version = "0.19.0", features = ["lmdb"] }
|
||||
|
||||
## tor
|
||||
arti-client = { version = "0.23.0", features = ["pt-client", "static", "onion-service-service", "onion-service-client"] }
|
||||
tor-rtcompat = { version = "0.23.0", features = ["static"] }
|
||||
tor-config = "0.23.0"
|
||||
fs-mistrust = "0.8.0"
|
||||
tor-hsservice = "0.23.0"
|
||||
tor-hsrproxy = "0.23.0"
|
||||
tor-keymgr = "0.23.0"
|
||||
tor-llcrypto = "0.23.0"
|
||||
tor-hscrypto = "0.23.0"
|
||||
tor-error = "0.23.0"
|
||||
arti-client = { version = "0.29.0", features = ["pt-client", "static", "onion-service-service", "onion-service-client"] }
|
||||
tor-rtcompat = { version = "0.29.0", features = ["static"] }
|
||||
tor-config = "0.29.0"
|
||||
fs-mistrust = "0.9.1"
|
||||
tor-hsservice = "0.29.0"
|
||||
tor-hsrproxy = "0.29.0"
|
||||
tor-keymgr = "0.29.0"
|
||||
tor-llcrypto = "0.29.0"
|
||||
tor-hscrypto = "0.29.0"
|
||||
tor-error = "0.29.0"
|
||||
sha2 = "0.10.8"
|
||||
ed25519-dalek = "2.1.1"
|
||||
curve25519-dalek = "4.1.3"
|
||||
hyper = { version = "0.14.30", features = ["full"] }
|
||||
hyper = { version = "0.14.31", features = ["full"] }
|
||||
hyper-tls = "0.5.0"
|
||||
tls-api = "0.9.0"
|
||||
tls-api-native-tls = "0.9.0"
|
||||
tls-api = "0.12.0"
|
||||
tls-api-native-tls = "0.12.1"
|
||||
|
||||
## stratum server
|
||||
tokio-old = {version = "0.2", features = ["full"], package = "tokio" }
|
||||
|
@ -107,8 +106,7 @@ nokhwa = { version = "0.10.5", default-features = false, features = ["input-v4l"
|
|||
nokhwa = { version = "0.10.5", default-features = false, features = ["input-msmf"] }
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
eye = { git = "https://github.com/raymanfx/eye-rs", rev = "5b7e3f7a1e79966091692896c568aab042e449ef", default-features = false }
|
||||
tls-api-openssl = "0.9.0"
|
||||
nokhwa-mac = { git = "https://github.com/l1npengtul/nokhwa", rev = "612c861ef153cf0ee575d8dd1413b960e4e19dd6", features = ["input-avfoundation", "output-threaded"], package = "nokhwa" }
|
||||
|
||||
[target.'cfg(not(target_os = "android"))'.dependencies]
|
||||
env_logger = "0.11.3"
|
||||
|
@ -127,7 +125,6 @@ winit = { version = "0.30.5", features = ["android-game-activity"] }
|
|||
eframe = { version = "0.29.1", features = ["wgpu", "android-game-activity"] }
|
||||
|
||||
[patch.crates-io]
|
||||
openpnp_capture = { git = "https://github.com/ardocrat/openpnp-capture-rs", rev = "f9b06f627c5e5d42c672d117650af700846ca6cf" }
|
||||
egui_extras = { git = "https://github.com/emilk/egui", rev = "5b846b4554fe47269affb43efef2cad8710a8a47" }
|
||||
egui = { git = "https://github.com/emilk/egui", rev = "5b846b4554fe47269affb43efef2cad8710a8a47" }
|
||||
eframe = { git = "https://github.com/emilk/egui", rev = "5b846b4554fe47269affb43efef2cad8710a8a47" }
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
# <img height="22" src="https://github.com/ardocrat/grim/blob/master/android/app/src/main/ic_launcher-playstore.png?raw=true"> Grim <img height="20" src="https://github.com/mimblewimble/site/blob/master/assets/images/grin-logo.png?raw=true"> <img height="20" src="https://github.com/ardocrat/grim/blob/master/img/logo.png?raw=true">
|
||||
# Grim <img height="20" src="https://gri.mw/code/GUI/grim/raw/branch/master/img/grin-logo.png"/> <img height="20" src="https://gri.mw/code/GUI/grim/raw/branch/master/img/logo.png"/>
|
||||
Cross-platform GUI for [GRiN ツ](https://grin.mw) in [Rust](https://www.rust-lang.org/)
|
||||
for maximum compatibility with original [Mimblewimble](https://github.com/mimblewimble/grin) implementation.
|
||||
Initially supported platforms are Linux, Mac, Windows, limited Android and possible web support with help of [egui](https://github.com/emilk/egui) - immediate mode GUI library in pure Rust.
|
||||
|
||||
Named by the character [Grim](http://harrypotter.wikia.com/wiki/Grim) - the shape of a large, black, menacing, spectral giant dog.
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
## Build instructions
|
||||
|
|
|
@ -11,7 +11,7 @@ android {
|
|||
minSdk 24
|
||||
targetSdk 33
|
||||
versionCode 3
|
||||
versionName "0.2.2"
|
||||
versionName "0.2.4"
|
||||
}
|
||||
|
||||
def keystorePropertiesFile = rootProject.file("keystore.properties")
|
||||
|
|
BIN
img/cover.png
Normal file
BIN
img/cover.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 181 KiB |
BIN
img/grin-logo.png
Normal file
BIN
img/grin-logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 37 KiB |
|
@ -4,7 +4,7 @@ case $2 in
|
|||
x86_64|arm)
|
||||
;;
|
||||
*)
|
||||
echo "Usage: release_linux.sh [version] [platform]\n - platform: 'x86_64', 'arm'" >&2
|
||||
echo "Usage: release_linux.sh [platform] [version]\n - platform: 'x86_64', 'arm'" >&2
|
||||
exit 1
|
||||
esac
|
||||
|
||||
|
@ -17,9 +17,11 @@ cd ..
|
|||
[[ $2 == "x86_64" ]] && arch+=(x86_64-unknown-linux-gnu)
|
||||
[[ $2 == "arm" ]] && arch+=(aarch64-unknown-linux-gnu)
|
||||
|
||||
cargo build --release --target ${arch}
|
||||
rustup target add ${arch}
|
||||
cargo install cargo-zigbuild
|
||||
cargo zigbuild --release --target ${arch}
|
||||
|
||||
# Create AppImage with https://github.com/AppImage/appimagetool
|
||||
cp target/${arch}/release/grim linux/Grim.AppDir/AppRun
|
||||
rm target/${arch}/release/*.AppImage
|
||||
appimagetool linux/Grim.AppDir target/${arch}/release/grim-v$1-linux-$2.AppImage
|
||||
appimagetool linux/Grim.AppDir target/${arch}/release/grim-v$2-linux-$1.AppImage
|
294
locales/zh-CN.yml
Normal file
294
locales/zh-CN.yml
Normal file
|
@ -0,0 +1,294 @@
|
|||
lang_name: 英语
|
||||
copy: 复制
|
||||
paste: 粘贴
|
||||
continue: 继续
|
||||
complete: 完成
|
||||
error: 错误
|
||||
retry: 重试
|
||||
close: 关闭
|
||||
change: 更改
|
||||
show: 显示
|
||||
delete: 删除
|
||||
clear: 清楚
|
||||
create: 创建
|
||||
id: 标识
|
||||
kernel: 核心
|
||||
settings: 设置
|
||||
language: 语言
|
||||
scan: 扫描
|
||||
qr_code: 二维码
|
||||
scan_qr: 扫描二维码
|
||||
repeat: 重复
|
||||
scan_result: 扫描结果
|
||||
back: 返回
|
||||
share: 分享
|
||||
theme: '主题:'
|
||||
dark: 深色
|
||||
light: 淡色
|
||||
choose_file: 选择文件
|
||||
crash_report: 崩溃报告
|
||||
crash_report_warning: 上次应用程序意外关闭,您可以报告开发人员崩溃事件.
|
||||
confirmation: 确认
|
||||
wallets:
|
||||
await_conf_amount: 等待确认中
|
||||
await_fin_amount: 等待确定中
|
||||
locked_amount: 锁定帐户
|
||||
txs_empty: '手动接收资金或通过传输接收资金 %{message} or %{transport} 更改钱包设置, 请按屏幕底部的按钮 %{settings} 按钮.'
|
||||
title: 钱包
|
||||
create_desc: 创建或种子单词导入已有钱包.
|
||||
add: 添加钱包
|
||||
name: '用户名:'
|
||||
pass: '密码:'
|
||||
pass_empty: 输入钱包的密码
|
||||
current_pass: '目前密码:'
|
||||
new_pass: '新密码:'
|
||||
min_tx_conf_count: '确认交易的最低数量:'
|
||||
recover: 恢复
|
||||
recovery_phrase: 助记词
|
||||
words_count: '字数:'
|
||||
enter_word: '输入单词 #%{number}:'
|
||||
not_valid_word: 输入的单词无效
|
||||
not_valid_phrase: 输入的助记词无效
|
||||
create_phrase_desc: 已安全地写下并保存助记词.
|
||||
restore_phrase_desc: 从已保存的助记词中输入.
|
||||
setup_conn_desc: 选择钱包连接到网络的方式.
|
||||
conn_method: 连接方式
|
||||
ext_conn: '外部连接:'
|
||||
add_node: 添加节点
|
||||
node_url: '节点网址:'
|
||||
node_secret: 'API 密钥 (可选):'
|
||||
invalid_url: 输入的网址无效
|
||||
open: 打开钱包
|
||||
wrong_pass: 输入的密码错误
|
||||
locked: 已锁定
|
||||
unlocked: 解锁
|
||||
enable_node: '通过选择屏幕底部的按钮 %{settings} 启用集成节点以使用钱包或更改连接设置.'
|
||||
node_loading: '集成节点同步后钱包会加载,你可选择屏幕底部的按钮 %{settings} 更改连接.'
|
||||
loading: 正在加载
|
||||
closing: 正在关闭
|
||||
checking: 检查中
|
||||
default_wallet: 默认钱包
|
||||
new_account_desc: '输入新帐户的名称:'
|
||||
wallet_loading: 加载钱包
|
||||
wallet_closing: 关闭钱包
|
||||
wallet_checking: 检查钱包
|
||||
tx_loading: 加载事务
|
||||
default_account: 默认账户
|
||||
accounts: 账户
|
||||
tx_sent: 已发送
|
||||
tx_received: 已接收
|
||||
tx_sending: 发送中
|
||||
tx_receiving: 接收中
|
||||
tx_confirming: 等待确认
|
||||
tx_canceled: 已取消
|
||||
tx_cancelling: 取消
|
||||
tx_finalizing: 完成
|
||||
tx_confirmed: 已确认
|
||||
txs: 所有交易
|
||||
tx: 交易
|
||||
messages: 消息
|
||||
transport: 传输
|
||||
input_slatepack_desc: '输入收到的 Slatepack 消息创建响应或完成的请求:'
|
||||
parse_slatepack_err: '读取消息时出错,请检查输入:'
|
||||
pay_balance_error: '账户余额不足以支付 %{amount} ツ 和网络费用.'
|
||||
parse_i1_slatepack_desc: '要支付 %{amount} ツ 请将此消息发送给接收者:'
|
||||
parse_i2_slatepack_desc: '完成交易以接收 %{amount} ツ:'
|
||||
parse_i3_slatepack_desc: '发布交易以完成 %{amount} ツ的接收 ツ:'
|
||||
parse_s1_slatepack_desc: '要接收 %{amount} ツ 请将此消息发送给发件人:'
|
||||
parse_s2_slatepack_desc: '完成交易以发送 %{amount} ツ:'
|
||||
parse_s3_slatepack_desc: '发布交易以完成 %{amount} ツ的发送:'
|
||||
resp_slatepack_err: '创建响应时出错,请检查输入数据或重试:'
|
||||
resp_exists_err: 此交易已存在.
|
||||
resp_canceled_err: 此交易已被取消.
|
||||
create_request_desc: '创建发送或接收资金的请求:'
|
||||
send_request_desc: '您已创建发送请求 %{amount} ツ. 将此消息发送给接收者:'
|
||||
send_slatepack_err: 创建发送资金请求时出错,请检查输入数据或重试.
|
||||
invoice_desc: '您已创建接收请求 %{amount} ツ. 将此消息发送给发送者:'
|
||||
invoice_slatepack_err: 发票开具时出错,请检查输入数据或重试.
|
||||
finalize_slatepack_err: '完结时出错,请检查输入数据或重试:'
|
||||
finalize: 完成
|
||||
use_dandelion: 使用蒲公英
|
||||
enter_amount_send: '你有 %{amount} ツ. 输入要发送的金额:'
|
||||
enter_amount_receive: '输入要接收的金额:'
|
||||
recovery: 恢复
|
||||
repair_wallet: 修复钱包
|
||||
repair_desc: 检查钱包,必要时修复和恢复丢失的输出. 此操作需要时间.
|
||||
repair_unavailable: 您需要与节点建立有效连接并完成钱包同步.
|
||||
delete: 删除钱包
|
||||
delete_conf: 您确定要删除钱包吗?
|
||||
delete_desc: 确保您已保存恢复助记语,以便日后使用资金。.
|
||||
wallet_loading_err: '同步钱包时出错,你可以通过选择屏幕底部的按钮 %{settings} 来重试或更改连接设置.'
|
||||
wallet: 钱包
|
||||
send: 发送
|
||||
receive: 接收
|
||||
settings: 钱包设置
|
||||
tx_send_cancel_conf: '您确定要取消 %{amount} ツ的发送吗?'
|
||||
tx_receive_cancel_conf: '您确定要取消 %{amount} ツ的接收吗?'
|
||||
rec_phrase_not_found: 找不到恢复助记词.
|
||||
restore_wallet_desc: 如果常规修复没有帮助,通过删除所有文件来恢复钱包.您将需要重新打开您的钱包.
|
||||
transport:
|
||||
desc: '使用传输同步接收或发送消息:'
|
||||
tor_network: Tor 网络
|
||||
connected: 已连接
|
||||
connecting: 正在连接
|
||||
disconnecting: 断开连接
|
||||
conn_error: 连接错误
|
||||
disconnected: 已断开连接
|
||||
receiver_address: '接收者的地址:'
|
||||
incorrect_addr_err: '输入的地址不正确:'
|
||||
tor_send_error: 通过 Tor 发送时出错,请确保接收方在线, 交易已取消.
|
||||
tor_autorun_desc: 是否在开钱包时启动 Tor 服务以同步接收交易.
|
||||
tor_sending: '通过 Tor 发送%{amount} ツ'
|
||||
tor_settings: Tor 设置
|
||||
bridges: 桥梁
|
||||
bridges_desc: 如果常规连接不正常,设置网桥,可以绕过 Tor 网络审查.
|
||||
bin_file: '二进制文件:'
|
||||
conn_line: '连接线:'
|
||||
bridges_disabled: 网桥已禁用
|
||||
bridge_name: '网桥%{b}'
|
||||
network:
|
||||
self: 网络
|
||||
type: '网络类型:'
|
||||
mainnet: 主网
|
||||
testnet: 测试网
|
||||
connections: 连接
|
||||
node: 集成节点
|
||||
metrics: 指标
|
||||
mining: 挖矿
|
||||
settings: 节点设置
|
||||
enable_node: 启用节点
|
||||
autorun: 自动运行
|
||||
disabled_server: '按屏幕左上角的按钮 %{dots}启用集成节点或添加其他连接方法.'
|
||||
no_ips: T您的系统上没有可用的 IP 地址,服务器无法启动,请检查您的网络连接.
|
||||
available: 可用
|
||||
not_available: 不可用
|
||||
availability_check: 检查是否可用
|
||||
android_warning: Android 用户注意 .要成功同步集成节点,您必须在手机的系统设置中允许访问通知并取消 Grim 应用程序的电池使用限制.这是在后台正确运行应用程序的必要操作.
|
||||
sync_status:
|
||||
node_restarting: 节点正在重新启动
|
||||
node_down: 节点已关闭
|
||||
initial: 节点正在启动
|
||||
no_sync: 节点正在运行
|
||||
awaiting_peers: 等待网络对点
|
||||
header_sync: 正下载标题
|
||||
header_sync_percent: '正在下载标题: %{percent}%'
|
||||
tx_hashset_pibd: 下载状态 (PIBD)
|
||||
tx_hashset_pibd_percent: '下载状态 (PIBD): %{percent}%'
|
||||
tx_hashset_download: 正在下载状态
|
||||
tx_hashset_download_percent: '下载状态: %{percent}%'
|
||||
tx_hashset_setup_history: '正在准备状态(历史记录): %{percent}%'
|
||||
tx_hashset_setup_position: '正在准备状态(位置): %{percent}%'
|
||||
tx_hashset_setup: 正在准备状态
|
||||
tx_hashset_range_proofs_validation: '验证状态(范围证明): %{percent}%'
|
||||
tx_hashset_kernels_validation: '正在验证状态(核心): %{percent}%'
|
||||
tx_hashset_save: 最终确定链状态
|
||||
body_sync: 下载区块
|
||||
body_sync_percent: '下载区块中: %{percent}%'
|
||||
shutdown: 节点正在关闭
|
||||
network_node:
|
||||
header: 标题
|
||||
block: 区块
|
||||
hash: 哈希值
|
||||
height: 高度
|
||||
difficulty: 难度
|
||||
time: 时间
|
||||
main_pool: 主池
|
||||
stem_pool: stem池
|
||||
data: 数据
|
||||
size: 大小 (GB)
|
||||
peers: 网络对点
|
||||
error_clean: 点数据已损坏,需要重新同步.
|
||||
resync: 重新同步
|
||||
error_p2p_api: '%{p2p_api} 服务器初始化时出错,请选择屏幕底部的按钮 %{p2p_api} 来检查 %{settings}设置.'
|
||||
error_config: '配置初始化时出错,请选择屏幕底部的按钮 %{settings} 检查设置.'
|
||||
error_unknown: '初始化时出错,请选择屏幕底部的按钮 %{settings} 来检查集成节点设置,或者重新同步.'
|
||||
network_metrics:
|
||||
loading: 指标在同步后将可用
|
||||
emission: 发射
|
||||
inflation: 通货膨胀
|
||||
supply: 供应
|
||||
block_time: Block time
|
||||
reward: 奖励
|
||||
difficulty_window: '难度窗口 %{size}'
|
||||
network_mining:
|
||||
loading: 同步后即可挖矿
|
||||
info: '挖矿服务器已启用,您可以通过选择屏幕底部的按钮 %{settings} 来更改其设置。连接设备后,数据会更新.'
|
||||
restart_server_required: 需要重启服务器才能应用更改.
|
||||
rewards_wallet: 奖励钱包
|
||||
server: 阶层服务器
|
||||
address: 地址
|
||||
miners: 矿工
|
||||
devices: 设备
|
||||
blocks_found: 找到的区块
|
||||
hashrate: '哈希率 (C%{bits})'
|
||||
connected: 已连接
|
||||
disconnected: 已断开连接
|
||||
network_settings:
|
||||
change_value: 更改值
|
||||
stratum_ip: '层 IP 地址:'
|
||||
stratum_port: '层端口:'
|
||||
port_unavailable: 指定的端口不可用
|
||||
restart_node_required: 需要重启节点才能应用更改.
|
||||
choose_wallet: 选择钱包
|
||||
stratum_wallet_warning: 必须打开钱包才能获得奖励.
|
||||
enable: 启用
|
||||
disable: 禁用
|
||||
restart: 重新启动
|
||||
server: 服务器
|
||||
api_ip: 'API IP 地址:'
|
||||
api_port: 'API 端口:'
|
||||
api_secret: '其它API 和 V2 所有者 API 令牌:'
|
||||
foreign_api_secret: '外部 API 令牌:'
|
||||
disabled: 已禁用
|
||||
enabled: 已启用
|
||||
ftl: '未来时间限制 (FTL):'
|
||||
ftl_description: 限制未来多长时间, 相对于节点的本地时间,以秒为单位, 新区块的时间戳可以被接受.
|
||||
not_valid_value: 输入的值无效
|
||||
full_validation: 完全验证
|
||||
full_validation_description: 在处理每个区块时是否运行全链验证(同步期间除外).
|
||||
archive_mode: 存档模式
|
||||
archive_mode_desc: 以全部存档模式运行全节点(同步需要更多的磁盘空间和时间).
|
||||
attempt_time: '尝试挖矿时间 (秒):'
|
||||
attempt_time_desc: 在停止并从池中重新收集交易之前尝试对特定标题进行挖矿的时间
|
||||
min_share_diff: '可接受的最低份额难度:'
|
||||
reset_settings_desc: 将节点设置重置为默认值
|
||||
reset_settings: 重置设置
|
||||
reset: 重置
|
||||
tx_pool: 交易池
|
||||
pool_fee: '接受到矿池的基本费用:'
|
||||
reorg_period: '重组缓存保留期(以分钟为单位):'
|
||||
max_tx_pool: '池中的最大交易数:'
|
||||
max_tx_stempool: 'stem池中的最大交易数:'
|
||||
max_tx_weight: '可以选择构建区块交易的最大总权重:'
|
||||
epoch_duration: '纪元持续时间(以秒为单位):'
|
||||
embargo_timer: '禁止计时器(以秒为单位):'
|
||||
aggregation_period: '聚合周期(以秒为单位):'
|
||||
stem_probability: 'stem助记词概率:'
|
||||
stem_txs: stem交易
|
||||
p2p_server: P2P 服务器
|
||||
p2p_port: 'P2P 端口:'
|
||||
add_seed: 添加 DNS 种子
|
||||
seed_address: 'DNS 种子地址:'
|
||||
add_peer: 添加网络对点
|
||||
peer_address: '网络对点地址:'
|
||||
peer_address_error: '以正确的格式输入 IP 地址或 DNS 名称(确保指定的主机可用),例如:192.168.0.1:1234 或 example.com:5678'
|
||||
default: 默认
|
||||
allow_list: 允许列表
|
||||
allow_list_desc: 仅连接到此列表中的网络对点.
|
||||
deny_list: 拒绝列表
|
||||
deny_list_desc: 切勿连接到此列表中的网络对点.
|
||||
favourites: 收藏夹
|
||||
favourites_desc: 要连接的首选网络对点列表.
|
||||
ban_window: '被封禁的网络对点应该保持被封禁多长时间(以秒为单位):'
|
||||
ban_window_desc: 禁止的决定是由节点 根据从网络对点收到的数据的正确性做出的.
|
||||
max_inbound_count: '入站网络对点连接的最大数量:'
|
||||
max_outbound_count: '最大出站网络对点连接数:'
|
||||
reset_peers_desc: 重置网络对点数据。仅当查找网络对点出现问题时,才请谨慎使用它.
|
||||
reset_peers: 重置网络对点
|
||||
modal:
|
||||
cancel: 取消
|
||||
save: 保存
|
||||
add: 添加
|
||||
modal_exit:
|
||||
description: 您确定要退出应用程序吗?
|
||||
exit: 退出
|
|
@ -21,7 +21,7 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.2.2</string>
|
||||
<string>0.2.3</string>
|
||||
<key>CFBundleSupportedPlatforms</key>
|
||||
<array>
|
||||
<string>MacOSX</string>
|
||||
|
|
|
@ -27,23 +27,11 @@ cd ..
|
|||
[[ $1 == "x86_64" ]] && arch+=(x86_64-apple-darwin)
|
||||
[[ $1 == "arm" ]] && arch+=(aarch64-apple-darwin)
|
||||
|
||||
if [[ "$OSTYPE" != "darwin"* ]]; then
|
||||
# Start release build on non-MacOS with zig linker, requires zig 0.12.1
|
||||
rustup target add x86_64-apple-darwin
|
||||
rustup target add aarch64-apple-darwin
|
||||
[[ $1 == "universal" ]]; arch+=(universal2-apple-darwin)
|
||||
cargo install cargo-zigbuild
|
||||
cargo zigbuild --release --target ${arch}
|
||||
else
|
||||
rustup target add ${arch}
|
||||
if [[ $1 == "universal" ]]; then
|
||||
cargo build --release --target x86_64-apple-darwin
|
||||
cargo build --release --target aarch64-apple-darwin
|
||||
lipo -create -output target/grim target/aarch64-apple-darwin/release/grim target/x86_64-apple-darwin/release/grim
|
||||
else
|
||||
cargo build --release --target ${arch}
|
||||
fi
|
||||
fi
|
||||
rustup target add x86_64-apple-darwin
|
||||
rustup target add aarch64-apple-darwin
|
||||
[[ $1 == "universal" ]]; arch+=(universal2-apple-darwin)
|
||||
cargo install cargo-zigbuild
|
||||
cargo zigbuild --release --target ${arch}
|
||||
|
||||
rm -f .intentionally-empty-file.o
|
||||
|
||||
|
|
|
@ -63,8 +63,8 @@ function build_apk() {
|
|||
./gradlew clean
|
||||
# Build signed apk if keystore exists
|
||||
if [ ! -f keystore.properties ]; then
|
||||
./gradlew assembleRelease
|
||||
apk_path=app/build/outputs/apk/release/app-release.apk
|
||||
./gradlew assembleDebug
|
||||
apk_path=app/build/outputs/apk/debug/app-debug.apk
|
||||
else
|
||||
./gradlew assembleSignedRelease
|
||||
apk_path=app/build/outputs/apk/signedRelease/app-signedRelease.apk
|
||||
|
|
|
@ -70,13 +70,11 @@ else
|
|||
exit 1
|
||||
fi
|
||||
|
||||
# ==================================
|
||||
# Update Android build.gradle file
|
||||
# and package version at Cargo.toml
|
||||
# ==================================
|
||||
|
||||
# Update version in build.gradle
|
||||
# Update version for Windows installer.
|
||||
sed -i '' -e 's/" Version="[^\"]*"/" Version="'"$VERSION_NEXT"'"/g' wix/main.wxs
|
||||
sed -i '' -e 's/<Package Id="[^\"]*"/<Package Id="'"$(uuidgen)"'"/g' wix/main.wxs
|
||||
|
||||
# Update Android version in build.gradle
|
||||
sed -i'.bak' -e 's/versionName [0-9a-zA-Z -_]*/versionName "'"$VERSION_NEXT"'"/' android/app/build.gradle
|
||||
rm -f android/app/build.gradle.bak
|
||||
|
||||
|
|
50
src/gui/app.rs
Normal file → Executable file
50
src/gui/app.rs
Normal file → Executable file
|
@ -16,7 +16,6 @@ use std::sync::atomic::{AtomicBool, Ordering};
|
|||
use lazy_static::lazy_static;
|
||||
use egui::{Align, Context, CursorIcon, Layout, Modifiers, ResizeDirection, Rounding, Stroke, UiBuilder, ViewportCommand};
|
||||
use egui::epaint::{RectShape};
|
||||
use egui::os::OperatingSystem;
|
||||
|
||||
use crate::AppConfig;
|
||||
use crate::gui::Colors;
|
||||
|
@ -108,16 +107,25 @@ impl<Platform: PlatformCallbacks> App<Platform> {
|
|||
let is_fullscreen = ui.ctx().input(|i| {
|
||||
i.viewport().fullscreen.unwrap_or(false)
|
||||
});
|
||||
if OperatingSystem::from_target_os() != OperatingSystem::Mac {
|
||||
self.desktop_window_ui(ui, is_fullscreen);
|
||||
} else {
|
||||
self.window_title_ui(ui, is_fullscreen);
|
||||
ui.add_space(-1.0);
|
||||
Self::title_panel_bg(ui);
|
||||
self.content.ui(ui, &self.platform);
|
||||
let os = egui::os::OperatingSystem::from_target_os();
|
||||
match os {
|
||||
egui::os::OperatingSystem::Mac => {
|
||||
self.window_title_ui(ui, is_fullscreen);
|
||||
ui.add_space(-1.0);
|
||||
Self::title_panel_bg(ui, true);
|
||||
self.content.ui(ui, &self.platform);
|
||||
}
|
||||
egui::os::OperatingSystem::Windows => {
|
||||
Self::title_panel_bg(ui, false);
|
||||
self.content.ui(ui, &self.platform);
|
||||
}
|
||||
_ => {
|
||||
self.custom_frame_ui(ui, is_fullscreen);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.mobile_window_ui(ui);
|
||||
Self::title_panel_bg(ui, false);
|
||||
self.content.ui(ui, &self.platform);
|
||||
}
|
||||
|
||||
// Provide incoming data to wallets.
|
||||
|
@ -135,14 +143,8 @@ impl<Platform: PlatformCallbacks> App<Platform> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Draw mobile platform window content.
|
||||
fn mobile_window_ui(&mut self, ui: &mut egui::Ui) {
|
||||
Self::title_panel_bg(ui);
|
||||
self.content.ui(ui, &self.platform);
|
||||
}
|
||||
|
||||
/// Draw desktop platform window content.
|
||||
fn desktop_window_ui(&mut self, ui: &mut egui::Ui, is_fullscreen: bool) {
|
||||
/// Draw custom desktop window frame content.
|
||||
fn custom_frame_ui(&mut self, ui: &mut egui::Ui, is_fullscreen: bool) {
|
||||
let content_bg_rect = {
|
||||
let mut r = ui.max_rect();
|
||||
if !is_fullscreen {
|
||||
|
@ -169,7 +171,7 @@ impl<Platform: PlatformCallbacks> App<Platform> {
|
|||
ui.add_space(-1.0);
|
||||
|
||||
// Draw title panel background.
|
||||
Self::title_panel_bg(ui);
|
||||
Self::title_panel_bg(ui, true);
|
||||
|
||||
let content_rect = {
|
||||
let mut rect = ui.max_rect();
|
||||
|
@ -197,10 +199,10 @@ impl<Platform: PlatformCallbacks> App<Platform> {
|
|||
}
|
||||
|
||||
/// Draw title panel background.
|
||||
fn title_panel_bg(ui: &mut egui::Ui) {
|
||||
fn title_panel_bg(ui: &mut egui::Ui, window_title: bool) {
|
||||
let title_rect = {
|
||||
let mut rect = ui.max_rect();
|
||||
if View::is_desktop() {
|
||||
if window_title {
|
||||
rect.min.y += Content::WINDOW_TITLE_HEIGHT - 0.5;
|
||||
}
|
||||
rect.max.y = rect.min.y + View::get_top_inset() + TitlePanel::HEIGHT;
|
||||
|
@ -223,7 +225,7 @@ impl<Platform: PlatformCallbacks> App<Platform> {
|
|||
r.max.y += TitlePanel::HEIGHT - 1.0;
|
||||
r
|
||||
};
|
||||
let is_mac = OperatingSystem::from_target_os() == OperatingSystem::Mac;
|
||||
let is_mac = egui::os::OperatingSystem::from_target_os() == egui::os::OperatingSystem::Mac;
|
||||
let window_title_bg = RectShape::new(title_bg_rect, if is_fullscreen || is_mac {
|
||||
Rounding::ZERO
|
||||
} else {
|
||||
|
@ -401,8 +403,10 @@ impl<Platform: PlatformCallbacks> eframe::App for App<Platform> {
|
|||
}
|
||||
|
||||
fn clear_color(&self, _visuals: &egui::Visuals) -> [f32; 4] {
|
||||
let is_mac = OperatingSystem::from_target_os() == OperatingSystem::Mac;
|
||||
if !View::is_desktop() || is_mac {
|
||||
let os = egui::os::OperatingSystem::from_target_os();
|
||||
let is_win = os == egui::os::OperatingSystem::Windows;
|
||||
let is_mac = os == egui::os::OperatingSystem::Mac;
|
||||
if !View::is_desktop() || is_win || is_mac {
|
||||
return Colors::fill_lite().to_normalized_gamma_f32();
|
||||
}
|
||||
Colors::TRANSPARENT.to_normalized_gamma_f32()
|
||||
|
|
|
@ -52,7 +52,7 @@ impl Desktop {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
// #[allow(dead_code)]
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
fn start_camera_capture(cameras_amount: Arc<AtomicUsize>,
|
||||
camera_index: Arc<AtomicUsize>,
|
||||
|
@ -109,52 +109,56 @@ impl Desktop {
|
|||
fn start_camera_capture(cameras_amount: Arc<AtomicUsize>,
|
||||
camera_index: Arc<AtomicUsize>,
|
||||
stop_camera: Arc<AtomicBool>) {
|
||||
use image::{ExtendedColorType, ImageBuffer, ImageEncoder, Rgb};
|
||||
use eye::hal::{traits::{Context, Device, Stream}, PlatformContext};
|
||||
use image::codecs::jpeg::JpegEncoder;
|
||||
use nokhwa_mac::nokhwa_initialize;
|
||||
use nokhwa_mac::pixel_format::RgbFormat;
|
||||
use nokhwa_mac::utils::{CameraIndex, RequestedFormat, RequestedFormatType};
|
||||
use nokhwa_mac::utils::ApiBackend;
|
||||
use nokhwa_mac::query;
|
||||
use nokhwa_mac::CallbackCamera;
|
||||
|
||||
let index = camera_index.load(Ordering::Relaxed);
|
||||
let devices = PlatformContext::default().devices().unwrap_or(vec![]);
|
||||
cameras_amount.store(devices.len(), Ordering::Relaxed);
|
||||
if devices.is_empty() || index >= devices.len() {
|
||||
return;
|
||||
}
|
||||
// Ask permission to open camera.
|
||||
nokhwa_initialize(|_| {});
|
||||
|
||||
// Capture images at separate thread.
|
||||
let uri = devices[camera_index.load(Ordering::Relaxed)].uri.clone();
|
||||
thread::spawn(move || {
|
||||
if let Ok(dev) = PlatformContext::default().open_device(&uri) {
|
||||
let streams = dev.streams().unwrap_or(vec![]);
|
||||
if streams.is_empty() {
|
||||
return;
|
||||
}
|
||||
let stream_desc = streams[0].clone();
|
||||
let w = stream_desc.width;
|
||||
let h = stream_desc.height;
|
||||
if let Ok(mut stream) = dev.start_stream(&stream_desc) {
|
||||
let cameras = query(ApiBackend::Auto).unwrap();
|
||||
cameras_amount.store(cameras.len(), Ordering::Relaxed);
|
||||
let index = camera_index.load(Ordering::Relaxed);
|
||||
if cameras.is_empty() || index >= cameras.len() {
|
||||
return;
|
||||
}
|
||||
// Start camera.
|
||||
let camera_index = CameraIndex::Index(camera_index.load(Ordering::Relaxed) as u32);
|
||||
let camera_callback = CallbackCamera::new(
|
||||
camera_index,
|
||||
RequestedFormat::new::<RgbFormat>(RequestedFormatType::AbsoluteHighestFrameRate),
|
||||
|_| {}
|
||||
);
|
||||
if let Ok(mut cb) = camera_callback {
|
||||
if cb.open_stream().is_ok() {
|
||||
loop {
|
||||
// Stop if camera was stopped.
|
||||
if stop_camera.load(Ordering::Relaxed) {
|
||||
stop_camera.store(false, Ordering::Relaxed);
|
||||
// Clear image.
|
||||
let mut w_image = LAST_CAMERA_IMAGE.write();
|
||||
*w_image = None;
|
||||
break;
|
||||
}
|
||||
// Get a frame.
|
||||
let frame = stream.next()
|
||||
.expect("Stream is dead")
|
||||
.expect("Failed to capture a frame");
|
||||
let mut out = vec![];
|
||||
if let Some(buf) = ImageBuffer::<Rgb<u8>, &[u8]>::from_raw(w, h, &frame) {
|
||||
JpegEncoder::new(&mut out)
|
||||
.write_image(buf.as_raw(), w, h, ExtendedColorType::Rgb8)
|
||||
.unwrap_or_default();
|
||||
// Get image from camera.
|
||||
if let Ok(frame) = cb.poll_frame() {
|
||||
let image = frame.decode_image::<RgbFormat>().unwrap();
|
||||
let mut bytes: Vec<u8> = Vec::new();
|
||||
let format = image::ImageFormat::Jpeg;
|
||||
// Convert image to Jpeg format.
|
||||
image.write_to(&mut std::io::Cursor::new(&mut bytes), format).unwrap();
|
||||
let mut w_image = LAST_CAMERA_IMAGE.write();
|
||||
*w_image = Some((bytes, 0));
|
||||
} else {
|
||||
out = frame.to_vec();
|
||||
// Clear image.
|
||||
let mut w_image = LAST_CAMERA_IMAGE.write();
|
||||
*w_image = None;
|
||||
break;
|
||||
}
|
||||
// Save image.
|
||||
let mut w_image = LAST_CAMERA_IMAGE.write();
|
||||
*w_image = Some((out, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -290,7 +290,7 @@ impl CameraContent {
|
|||
|
||||
// Launch scanner at separate thread.
|
||||
thread::spawn(move || {
|
||||
tokio::runtime::Builder::new_multi_thread()
|
||||
tokio::runtime::Builder::new_current_thread()
|
||||
.enable_all()
|
||||
.build()
|
||||
.unwrap()
|
||||
|
|
6
src/gui/views/modal.rs
Normal file → Executable file
6
src/gui/views/modal.rs
Normal file → Executable file
|
@ -185,7 +185,8 @@ impl Modal {
|
|||
});
|
||||
|
||||
// Setup background rect.
|
||||
let bg_rect = if View::is_desktop() {
|
||||
let is_win = OperatingSystem::Windows == OperatingSystem::from_target_os();
|
||||
let bg_rect = if View::is_desktop() && !is_win {
|
||||
let mut r = ctx.screen_rect();
|
||||
let is_mac = OperatingSystem::Mac == OperatingSystem::from_target_os();
|
||||
if !is_mac && !is_fullscreen {
|
||||
|
@ -255,7 +256,8 @@ impl Modal {
|
|||
|
||||
let x_align = View::get_left_inset() - View::get_right_inset();
|
||||
let is_mac = OperatingSystem::Mac == OperatingSystem::from_target_os();
|
||||
let extra_y = if View::is_desktop() {
|
||||
let is_win = OperatingSystem::Windows == OperatingSystem::from_target_os();
|
||||
let extra_y = if View::is_desktop() && !is_win {
|
||||
Content::WINDOW_TITLE_HEIGHT + if !is_mac {
|
||||
Content::WINDOW_FRAME_MARGIN
|
||||
} else {
|
||||
|
|
|
@ -105,7 +105,7 @@ impl ConnectionsContent {
|
|||
let ext_conn_size = ext_conn_list.len();
|
||||
if ext_conn_size != 0 {
|
||||
ui.add_space(8.0);
|
||||
for (index, conn) in ext_conn_list.iter().filter(|c| !c.deleted).enumerate() {
|
||||
for (index, conn) in ext_conn_list.iter().enumerate() {
|
||||
ui.horizontal_wrapped(|ui| {
|
||||
// Draw connection list item.
|
||||
Self::ext_conn_item_ui(ui, conn, index, ext_conn_size, |ui| {
|
||||
|
|
|
@ -187,7 +187,7 @@ impl NetworkContent {
|
|||
});
|
||||
|
||||
// Redraw after delay if node is running at non-dual-panel mode.
|
||||
if !dual_panel && Content::is_network_panel_open() && Node::is_running() {
|
||||
if ((!dual_panel && Content::is_network_panel_open()) || dual_panel) && Node::is_running() {
|
||||
ui.ctx().request_repaint_after(Node::STATS_UPDATE_DELAY);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -193,6 +193,11 @@ impl DandelionSetup {
|
|||
}
|
||||
};
|
||||
|
||||
// Continue on Enter key press.
|
||||
View::on_enter_key(ui, || {
|
||||
on_save();
|
||||
});
|
||||
|
||||
ui.columns(2, |columns| {
|
||||
columns[0].vertical_centered_justified(|ui| {
|
||||
View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || {
|
||||
|
@ -269,6 +274,11 @@ impl DandelionSetup {
|
|||
}
|
||||
};
|
||||
|
||||
// Continue on Enter key press.
|
||||
View::on_enter_key(ui, || {
|
||||
on_save();
|
||||
});
|
||||
|
||||
ui.columns(2, |columns| {
|
||||
columns[0].vertical_centered_justified(|ui| {
|
||||
View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || {
|
||||
|
@ -346,6 +356,11 @@ impl DandelionSetup {
|
|||
}
|
||||
};
|
||||
|
||||
// Continue on Enter key press.
|
||||
View::on_enter_key(ui, || {
|
||||
on_save();
|
||||
});
|
||||
|
||||
ui.columns(2, |columns| {
|
||||
columns[0].vertical_centered_justified(|ui| {
|
||||
View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || {
|
||||
|
@ -423,6 +438,11 @@ impl DandelionSetup {
|
|||
}
|
||||
};
|
||||
|
||||
// Continue on Enter key press.
|
||||
View::on_enter_key(ui, || {
|
||||
on_save();
|
||||
});
|
||||
|
||||
ui.columns(2, |columns| {
|
||||
columns[0].vertical_centered_justified(|ui| {
|
||||
View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || {
|
||||
|
|
|
@ -310,7 +310,7 @@ impl NodeSetup {
|
|||
ui.spacing_mut().item_spacing = egui::Vec2::new(8.0, 0.0);
|
||||
|
||||
// Save button callback.
|
||||
let on_save = || {
|
||||
let mut on_save = || {
|
||||
// Check if port is available.
|
||||
let (api_ip, _) = NodeConfig::get_api_ip_port();
|
||||
let available = NodeConfig::is_api_port_available(&api_ip, &self.api_port_edit);
|
||||
|
@ -330,6 +330,11 @@ impl NodeSetup {
|
|||
}
|
||||
};
|
||||
|
||||
// Continue on Enter key press.
|
||||
View::on_enter_key(ui, || {
|
||||
on_save();
|
||||
});
|
||||
|
||||
ui.columns(2, |columns| {
|
||||
columns[0].vertical_centered_justified(|ui| {
|
||||
View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || {
|
||||
|
@ -427,6 +432,11 @@ impl NodeSetup {
|
|||
modal.close();
|
||||
};
|
||||
|
||||
// Continue on Enter key press.
|
||||
View::on_enter_key(ui, || {
|
||||
on_save();
|
||||
});
|
||||
|
||||
ui.columns(2, |columns| {
|
||||
columns[0].vertical_centered_justified(|ui| {
|
||||
View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || {
|
||||
|
@ -509,6 +519,11 @@ impl NodeSetup {
|
|||
}
|
||||
};
|
||||
|
||||
// Continue on Enter key press.
|
||||
View::on_enter_key(ui, || {
|
||||
on_save();
|
||||
});
|
||||
|
||||
ui.columns(2, |columns| {
|
||||
columns[0].vertical_centered_justified(|ui| {
|
||||
View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || {
|
||||
|
|
|
@ -249,16 +249,16 @@ impl P2PSetup {
|
|||
View::button(ui,
|
||||
format!("{} {}", PLUG, &port),
|
||||
Colors::white_or_black(false), || {
|
||||
// Setup values for modal.
|
||||
self.port_edit = port;
|
||||
self.port_available_edit = self.is_port_available;
|
||||
// Show p2p port modal.
|
||||
Modal::new(PORT_MODAL)
|
||||
.position(ModalPosition::CenterTop)
|
||||
.title(t!("network_settings.change_value"))
|
||||
.show();
|
||||
cb.show_keyboard();
|
||||
});
|
||||
// Setup values for modal.
|
||||
self.port_edit = port;
|
||||
self.port_available_edit = self.is_port_available;
|
||||
// Show p2p port modal.
|
||||
Modal::new(PORT_MODAL)
|
||||
.position(ModalPosition::CenterTop)
|
||||
.title(t!("network_settings.change_value"))
|
||||
.show();
|
||||
cb.show_keyboard();
|
||||
});
|
||||
ui.add_space(6.0);
|
||||
|
||||
// Show error when p2p port is unavailable.
|
||||
|
@ -300,7 +300,7 @@ impl P2PSetup {
|
|||
ui.spacing_mut().item_spacing = egui::Vec2::new(8.0, 0.0);
|
||||
|
||||
// Save button callback.
|
||||
let on_save = || {
|
||||
let mut on_save = || {
|
||||
// Check if port is available.
|
||||
let available = NodeConfig::is_p2p_port_available(&self.port_edit);
|
||||
self.port_available_edit = available;
|
||||
|
@ -317,6 +317,11 @@ impl P2PSetup {
|
|||
}
|
||||
};
|
||||
|
||||
// Continue on Enter key press.
|
||||
View::on_enter_key(ui, || {
|
||||
on_save();
|
||||
});
|
||||
|
||||
ui.columns(2, |columns| {
|
||||
columns[0].vertical_centered_justified(|ui| {
|
||||
View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || {
|
||||
|
@ -370,8 +375,10 @@ impl P2PSetup {
|
|||
ui.label(RichText::new(desc)
|
||||
.size(16.0)
|
||||
.color(Colors::inactive_text()));
|
||||
ui.add_space(12.0);
|
||||
} else if !peers.is_empty() {
|
||||
ui.add_space(12.0);
|
||||
}
|
||||
ui.add_space(12.0);
|
||||
|
||||
let add_text = if peer_type == &PeerType::CustomSeed {
|
||||
format!("{} {}", PLUS_CIRCLE, t!("network_settings.add_seed"))
|
||||
|
@ -438,7 +445,7 @@ impl P2PSetup {
|
|||
ui.spacing_mut().item_spacing = egui::Vec2::new(8.0, 0.0);
|
||||
|
||||
// Save button callback.
|
||||
let on_save = || {
|
||||
let mut on_save = || {
|
||||
// Check if peer is correct and/or available.
|
||||
let peer = self.peer_edit.clone();
|
||||
let is_correct_address = PeersConfig::peer_to_addr(peer.clone()).is_some();
|
||||
|
@ -460,6 +467,11 @@ impl P2PSetup {
|
|||
}
|
||||
};
|
||||
|
||||
// Continue on Enter key press.
|
||||
View::on_enter_key(ui, || {
|
||||
on_save();
|
||||
});
|
||||
|
||||
ui.columns(2, |columns| {
|
||||
columns[0].vertical_centered_justified(|ui| {
|
||||
View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || {
|
||||
|
@ -509,15 +521,15 @@ impl P2PSetup {
|
|||
View::button(ui,
|
||||
format!("{} {}", PROHIBIT_INSET, &ban_window),
|
||||
Colors::white_or_black(false), || {
|
||||
// Setup values for modal.
|
||||
self.ban_window_edit = ban_window;
|
||||
// Show ban window period setup modal.
|
||||
Modal::new(BAN_WINDOW_MODAL)
|
||||
.position(ModalPosition::CenterTop)
|
||||
.title(t!("network_settings.change_value"))
|
||||
.show();
|
||||
cb.show_keyboard();
|
||||
});
|
||||
// Setup values for modal.
|
||||
self.ban_window_edit = ban_window;
|
||||
// Show ban window period setup modal.
|
||||
Modal::new(BAN_WINDOW_MODAL)
|
||||
.position(ModalPosition::CenterTop)
|
||||
.title(t!("network_settings.change_value"))
|
||||
.show();
|
||||
cb.show_keyboard();
|
||||
});
|
||||
ui.add_space(6.0);
|
||||
ui.label(RichText::new(t!("network_settings.ban_window_desc"))
|
||||
.size(16.0)
|
||||
|
@ -565,6 +577,11 @@ impl P2PSetup {
|
|||
}
|
||||
};
|
||||
|
||||
// Continue on Enter key press.
|
||||
View::on_enter_key(ui, || {
|
||||
on_save();
|
||||
});
|
||||
|
||||
ui.columns(2, |columns| {
|
||||
columns[0].vertical_centered_justified(|ui| {
|
||||
View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || {
|
||||
|
@ -593,15 +610,15 @@ impl P2PSetup {
|
|||
View::button(ui,
|
||||
format!("{} {}", ARROW_FAT_LINES_DOWN, &max_inbound),
|
||||
Colors::white_or_black(false), || {
|
||||
// Setup values for modal.
|
||||
self.max_inbound_count = max_inbound;
|
||||
// Show maximum number of inbound peers setup modal.
|
||||
Modal::new(MAX_INBOUND_MODAL)
|
||||
.position(ModalPosition::CenterTop)
|
||||
.title(t!("network_settings.change_value"))
|
||||
.show();
|
||||
cb.show_keyboard();
|
||||
});
|
||||
// Setup values for modal.
|
||||
self.max_inbound_count = max_inbound;
|
||||
// Show maximum number of inbound peers setup modal.
|
||||
Modal::new(MAX_INBOUND_MODAL)
|
||||
.position(ModalPosition::CenterTop)
|
||||
.title(t!("network_settings.change_value"))
|
||||
.show();
|
||||
cb.show_keyboard();
|
||||
});
|
||||
ui.add_space(6.0);
|
||||
}
|
||||
|
||||
|
@ -644,6 +661,11 @@ impl P2PSetup {
|
|||
}
|
||||
};
|
||||
|
||||
// Continue on Enter key press.
|
||||
View::on_enter_key(ui, || {
|
||||
on_save();
|
||||
});
|
||||
|
||||
ui.columns(2, |columns| {
|
||||
columns[0].vertical_centered_justified(|ui| {
|
||||
View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || {
|
||||
|
@ -671,15 +693,15 @@ impl P2PSetup {
|
|||
View::button(ui,
|
||||
format!("{} {}", ARROW_FAT_LINES_UP, &max_outbound),
|
||||
Colors::white_or_black(false), || {
|
||||
// Setup values for modal.
|
||||
self.max_outbound_count = max_outbound;
|
||||
// Show maximum number of outbound peers setup modal.
|
||||
Modal::new(MAX_OUTBOUND_MODAL)
|
||||
.position(ModalPosition::CenterTop)
|
||||
.title(t!("network_settings.change_value"))
|
||||
.show();
|
||||
cb.show_keyboard();
|
||||
});
|
||||
// Setup values for modal.
|
||||
self.max_outbound_count = max_outbound;
|
||||
// Show maximum number of outbound peers setup modal.
|
||||
Modal::new(MAX_OUTBOUND_MODAL)
|
||||
.position(ModalPosition::CenterTop)
|
||||
.title(t!("network_settings.change_value"))
|
||||
.show();
|
||||
cb.show_keyboard();
|
||||
});
|
||||
ui.add_space(6.0);
|
||||
}
|
||||
|
||||
|
@ -722,6 +744,11 @@ impl P2PSetup {
|
|||
}
|
||||
};
|
||||
|
||||
// Continue on Enter key press.
|
||||
View::on_enter_key(ui, || {
|
||||
on_save();
|
||||
});
|
||||
|
||||
ui.columns(2, |columns| {
|
||||
columns[0].vertical_centered_justified(|ui| {
|
||||
View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || {
|
||||
|
@ -745,9 +772,9 @@ impl P2PSetup {
|
|||
format!("{} {}", TRASH, t!("network_settings.reset_peers")),
|
||||
Colors::red(),
|
||||
Colors::white_or_black(false), || {
|
||||
Node::reset_peers(false);
|
||||
self.peers_reset = true;
|
||||
});
|
||||
Node::reset_peers(false);
|
||||
self.peers_reset = true;
|
||||
});
|
||||
ui.add_space(6.0);
|
||||
ui.label(RichText::new(t!("network_settings.reset_peers_desc"))
|
||||
.size(16.0)
|
||||
|
|
|
@ -195,6 +195,12 @@ impl PoolSetup {
|
|||
modal.close();
|
||||
}
|
||||
};
|
||||
|
||||
// Continue on Enter key press.
|
||||
View::on_enter_key(ui, || {
|
||||
on_save();
|
||||
});
|
||||
|
||||
ui.columns(2, |columns| {
|
||||
columns[0].vertical_centered_justified(|ui| {
|
||||
View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || {
|
||||
|
@ -273,6 +279,11 @@ impl PoolSetup {
|
|||
}
|
||||
};
|
||||
|
||||
// Continue on Enter key press.
|
||||
View::on_enter_key(ui, || {
|
||||
on_save();
|
||||
});
|
||||
|
||||
ui.columns(2, |columns| {
|
||||
columns[0].vertical_centered_justified(|ui| {
|
||||
View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || {
|
||||
|
@ -350,6 +361,11 @@ impl PoolSetup {
|
|||
}
|
||||
};
|
||||
|
||||
// Continue on Enter key press.
|
||||
View::on_enter_key(ui, || {
|
||||
on_save();
|
||||
});
|
||||
|
||||
ui.columns(2, |columns| {
|
||||
columns[0].vertical_centered_justified(|ui| {
|
||||
View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || {
|
||||
|
@ -429,6 +445,11 @@ impl PoolSetup {
|
|||
}
|
||||
};
|
||||
|
||||
// Continue on Enter key press.
|
||||
View::on_enter_key(ui, || {
|
||||
on_save();
|
||||
});
|
||||
|
||||
ui.columns(2, |columns| {
|
||||
columns[0].vertical_centered_justified(|ui| {
|
||||
View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || {
|
||||
|
@ -508,6 +529,11 @@ impl PoolSetup {
|
|||
}
|
||||
};
|
||||
|
||||
// Continue on Enter key press.
|
||||
View::on_enter_key(ui, || {
|
||||
on_save();
|
||||
});
|
||||
|
||||
ui.columns(2, |columns| {
|
||||
columns[0].vertical_centered_justified(|ui| {
|
||||
View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || {
|
||||
|
|
|
@ -316,7 +316,7 @@ impl StratumSetup {
|
|||
ui.spacing_mut().item_spacing = egui::Vec2::new(8.0, 0.0);
|
||||
|
||||
// Save button callback.
|
||||
let on_save = || {
|
||||
let mut on_save = || {
|
||||
// Check if port is available.
|
||||
let (stratum_ip, _) = NodeConfig::get_stratum_address();
|
||||
let available = NodeConfig::is_stratum_port_available(
|
||||
|
@ -335,6 +335,11 @@ impl StratumSetup {
|
|||
}
|
||||
};
|
||||
|
||||
// Continue on Enter key press.
|
||||
View::on_enter_key(ui, || {
|
||||
on_save();
|
||||
});
|
||||
|
||||
ui.columns(2, |columns| {
|
||||
columns[0].vertical_centered_justified(|ui| {
|
||||
View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || {
|
||||
|
@ -419,6 +424,11 @@ impl StratumSetup {
|
|||
}
|
||||
};
|
||||
|
||||
// Continue on Enter key press.
|
||||
View::on_enter_key(ui, || {
|
||||
on_save();
|
||||
});
|
||||
|
||||
ui.columns(2, |columns| {
|
||||
columns[0].vertical_centered_justified(|ui| {
|
||||
View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || {
|
||||
|
@ -497,6 +507,11 @@ impl StratumSetup {
|
|||
}
|
||||
};
|
||||
|
||||
// Continue on Enter key press.
|
||||
View::on_enter_key(ui, || {
|
||||
on_save();
|
||||
});
|
||||
|
||||
ui.columns(2, |columns| {
|
||||
columns[0].vertical_centered_justified(|ui| {
|
||||
View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || {
|
||||
|
|
|
@ -104,10 +104,7 @@ impl WalletConnectionModal {
|
|||
|
||||
if !ext_conn_list.is_empty() {
|
||||
ui.add_space(8.0);
|
||||
for (index, conn) in ext_conn_list.iter().filter(|c| !c.deleted).enumerate() {
|
||||
if conn.deleted {
|
||||
continue;
|
||||
}
|
||||
for (index, conn) in ext_conn_list.iter().enumerate() {
|
||||
ui.horizontal_wrapped(|ui| {
|
||||
let len = ext_conn_list.len();
|
||||
ConnectionsContent::ext_conn_item_ui(ui, conn, index, len, |ui| {
|
||||
|
|
|
@ -23,7 +23,7 @@ use crate::gui::Colors;
|
|||
use crate::gui::icons::{ARROWS_CLOCKWISE, BRIDGE, CAMERA_ROTATE, CHAT_CIRCLE_TEXT, FOLDER_USER, GEAR_FINE, GRAPH, PACKAGE, POWER, SCAN, SPINNER, USERS_THREE};
|
||||
use crate::gui::platform::PlatformCallbacks;
|
||||
use crate::gui::views::{Modal, Content, View, CameraContent};
|
||||
use crate::gui::views::types::{LinePosition, ModalContainer, ModalPosition};
|
||||
use crate::gui::views::types::{LinePosition, ModalContainer, ModalPosition, QrScanResult};
|
||||
use crate::gui::views::wallets::{WalletTransactions, WalletMessages, WalletTransport};
|
||||
use crate::gui::views::wallets::types::{GRIN, WalletTab, WalletTabType};
|
||||
use crate::gui::views::wallets::wallet::modals::WalletAccountsModal;
|
||||
|
@ -134,17 +134,33 @@ impl WalletContent {
|
|||
.show_animated_inside(ui, show_account, |ui| {
|
||||
let rect = ui.available_rect_before_wrap();
|
||||
if show_qr_scan {
|
||||
View::max_width_ui(ui, Content::SIDE_PANEL_WIDTH, |ui| {
|
||||
self.qr_scan_content.as_mut().unwrap().ui(ui, cb);
|
||||
ui.add_space(6.0);
|
||||
ui.vertical_centered_justified(|ui| {
|
||||
View::button(ui, t!("close"), Colors::white_or_black(false), || {
|
||||
cb.stop_camera();
|
||||
self.qr_scan_content = None;
|
||||
if let Some(result) = self.qr_scan_content.as_ref().unwrap().qr_scan_result() {
|
||||
match result {
|
||||
QrScanResult::Address(address) => {
|
||||
self.current_tab =
|
||||
Box::new(WalletTransport::new(Some(address.to_string()), cb));
|
||||
}
|
||||
_ => {
|
||||
self.current_tab =
|
||||
Box::new(WalletMessages::new(Some(result.text())))
|
||||
}
|
||||
}
|
||||
// Stop camera and close scanning.
|
||||
cb.stop_camera();
|
||||
self.qr_scan_content = None;
|
||||
} else {
|
||||
View::max_width_ui(ui, Content::SIDE_PANEL_WIDTH, |ui| {
|
||||
self.qr_scan_content.as_mut().unwrap().ui(ui, cb);
|
||||
ui.add_space(6.0);
|
||||
ui.vertical_centered_justified(|ui| {
|
||||
View::button(ui, t!("close"), Colors::white_or_black(false), || {
|
||||
cb.stop_camera();
|
||||
self.qr_scan_content = None;
|
||||
});
|
||||
});
|
||||
ui.add_space(6.0);
|
||||
});
|
||||
ui.add_space(6.0);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
View::max_width_ui(ui, Content::SIDE_PANEL_WIDTH * 1.3, |ui| {
|
||||
self.account_ui(ui, data.unwrap(), cb);
|
||||
|
@ -393,7 +409,7 @@ impl WalletContent {
|
|||
});
|
||||
columns[2].vertical_centered_justified(|ui| {
|
||||
View::tab_button(ui, BRIDGE, current_type == WalletTabType::Transport, |_| {
|
||||
self.current_tab = Box::new(WalletTransport::default());
|
||||
self.current_tab = Box::new(WalletTransport::new(None, cb));
|
||||
});
|
||||
});
|
||||
columns[3].vertical_centered_justified(|ui| {
|
||||
|
@ -502,4 +518,4 @@ fn sync_progress_ui(ui: &mut egui::Ui, wallet: &Wallet) {
|
|||
ui.label(RichText::new(text).size(16.0).color(Colors::inactive_text()));
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,7 +74,7 @@ impl ConnectionSettings {
|
|||
|
||||
/// Draw existing wallet connection setup content.
|
||||
pub fn wallet_ui(&mut self, ui: &mut egui::Ui, wallet: &Wallet, cb: &dyn PlatformCallbacks) {
|
||||
self.method = wallet.get_current_connection();
|
||||
self.method = wallet.get_current_connection();
|
||||
|
||||
// Draw setup content.
|
||||
let changed = self.ui(ui, cb);
|
||||
|
@ -133,31 +133,39 @@ impl ConnectionSettings {
|
|||
});
|
||||
ui.add_space(4.0);
|
||||
|
||||
// Check if it's current method.
|
||||
let is_current = |m: &ConnectionMethod, c: &ExternalConnection| -> Option<bool> {
|
||||
match m {
|
||||
ConnectionMethod::External(id, _) => if c.deleted && *id == c.id {
|
||||
None
|
||||
} else {
|
||||
Some(*id == c.id)
|
||||
},
|
||||
_ => Some(false)
|
||||
// Check for removed active connection.
|
||||
let cur_method = &self.method.clone();
|
||||
let mut ext_conn_list = ConnectionsConfig::ext_conn_list();
|
||||
let has_method = !ext_conn_list.iter().filter(|c| {
|
||||
match cur_method {
|
||||
ConnectionMethod::Integrated => true,
|
||||
ConnectionMethod::External(id, url) => id == &c.id || url == &c.url
|
||||
}
|
||||
};
|
||||
}).collect::<Vec<&ExternalConnection>>().is_empty();
|
||||
if !has_method {
|
||||
match cur_method {
|
||||
ConnectionMethod::External(id, url) => {
|
||||
ext_conn_list.push(ExternalConnection {
|
||||
id: *id,
|
||||
url: url.clone(),
|
||||
secret: None,
|
||||
available: Some(true),
|
||||
})
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
let method = &self.method.clone();
|
||||
let ext_conn_list = ConnectionsConfig::ext_conn_list();
|
||||
let ext_list = ext_conn_list.iter().filter(|c| {
|
||||
!c.deleted || is_current(method, c).unwrap_or(true)
|
||||
}).collect::<Vec<&ExternalConnection>>();
|
||||
let ext_size = ext_list.len();
|
||||
let ext_size = ext_conn_list.len();
|
||||
if ext_size != 0 {
|
||||
ui.add_space(8.0);
|
||||
|
||||
for (i, c) in ext_list.iter().enumerate() {
|
||||
for (i, c) in ext_conn_list.iter().enumerate() {
|
||||
ui.horizontal_wrapped(|ui| {
|
||||
// Draw external connection item.
|
||||
let is_current = is_current(method, c);
|
||||
let is_current = match cur_method {
|
||||
ConnectionMethod::External(id, url) => id == &c.id || url == &c.url,
|
||||
_ => false
|
||||
};
|
||||
Self::ext_conn_item_ui(ui, c, is_current, i, ext_size, || {
|
||||
self.method = ConnectionMethod::External(c.id, c.url.clone());
|
||||
changed = true;
|
||||
|
@ -172,7 +180,7 @@ impl ConnectionSettings {
|
|||
/// Draw external connection item content.
|
||||
fn ext_conn_item_ui(ui: &mut egui::Ui,
|
||||
conn: &ExternalConnection,
|
||||
is_current: Option<bool>,
|
||||
is_current: bool,
|
||||
index: usize,
|
||||
len: usize,
|
||||
mut on_select: impl FnMut()) {
|
||||
|
@ -187,7 +195,7 @@ impl ConnectionSettings {
|
|||
|
||||
ui.vertical(|ui| {
|
||||
ui.allocate_ui_with_layout(rect.size(), Layout::right_to_left(Align::Center), |ui| {
|
||||
if is_current.unwrap_or(true) {
|
||||
if is_current {
|
||||
ui.add_space(12.0);
|
||||
ui.label(RichText::new(CHECK_FAT).size(20.0).color(Colors::green()));
|
||||
} else {
|
||||
|
@ -210,11 +218,7 @@ impl ConnectionSettings {
|
|||
// Setup connection status text.
|
||||
let status_text = if let Some(available) = conn.available {
|
||||
if available {
|
||||
format!("{} {}", CHECK_CIRCLE, if is_current.is_none() {
|
||||
t!("transport.connected")
|
||||
} else {
|
||||
t!("network.available")
|
||||
})
|
||||
format!("{} {}", CHECK_CIRCLE, t!("network.available"))
|
||||
} else {
|
||||
format!("{} {}", X_CIRCLE, t!("network.not_available"))
|
||||
}
|
||||
|
|
|
@ -54,24 +54,25 @@ impl WalletTab for WalletTransport {
|
|||
|
||||
/// Identifier for [`Modal`] to send amount over Tor.
|
||||
const SEND_TOR_MODAL: &'static str = "send_tor_modal";
|
||||
|
||||
/// Identifier for [`Modal`] to setup Tor service.
|
||||
const TOR_SETTINGS_MODAL: &'static str = "tor_settings_modal";
|
||||
|
||||
/// Identifier for [`Modal`] to show QR code address image.
|
||||
const QR_ADDRESS_MODAL: &'static str = "qr_address_modal";
|
||||
|
||||
impl Default for WalletTransport {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
impl WalletTransport {
|
||||
/// Create new transport content instance, opening sending `Modal` if address was provided.
|
||||
pub fn new(address: Option<String>, cb: &dyn PlatformCallbacks) -> Self {
|
||||
let mut content = Self {
|
||||
send_modal_content: None,
|
||||
qr_address_content: None,
|
||||
settings_modal_content: None,
|
||||
};
|
||||
if address.is_some() {
|
||||
content.show_send_tor_modal(cb, address)
|
||||
}
|
||||
content
|
||||
}
|
||||
}
|
||||
|
||||
impl WalletTransport {
|
||||
/// Draw wallet transport content.
|
||||
fn transport_ui(&mut self, ui: &mut egui::Ui, wallet: &Wallet, cb: &dyn PlatformCallbacks) {
|
||||
ui.add_space(3.0);
|
||||
|
@ -352,7 +353,7 @@ impl WalletTransport {
|
|||
}
|
||||
|
||||
/// Show [`Modal`] to send over Tor.
|
||||
pub fn show_send_tor_modal(&mut self, cb: &dyn PlatformCallbacks, address: Option<String>) {
|
||||
fn show_send_tor_modal(&mut self, cb: &dyn PlatformCallbacks, address: Option<String>) {
|
||||
self.send_modal_content = Some(TransportSendModal::new(address));
|
||||
// Show modal.
|
||||
Modal::new(SEND_TOR_MODAL)
|
||||
|
|
|
@ -18,11 +18,9 @@ use egui::{Id, RichText};
|
|||
use grin_core::core::{amount_from_hr_string, amount_to_hr_string};
|
||||
use grin_wallet_libwallet::{Error, SlatepackAddress};
|
||||
use parking_lot::RwLock;
|
||||
use tor_rtcompat::BlockOn;
|
||||
use tor_rtcompat::tokio::TokioNativeTlsRuntime;
|
||||
|
||||
use crate::gui::Colors;
|
||||
use crate::gui::platform::PlatformCallbacks;
|
||||
|
||||
use crate::gui::views::{CameraContent, Modal, View};
|
||||
use crate::gui::views::types::TextEditOptions;
|
||||
use crate::gui::views::wallets::wallet::WalletTransactionModal;
|
||||
|
@ -302,7 +300,7 @@ impl TransportSendModal {
|
|||
return;
|
||||
}
|
||||
let addr_str = self.address_edit.as_str();
|
||||
if let Ok(addr) = SlatepackAddress::try_from(addr_str) {
|
||||
if let Ok(addr) = SlatepackAddress::try_from(addr_str.trim()) {
|
||||
if let Ok(a) = amount_from_hr_string(self.amount_edit.as_str()) {
|
||||
cb.hide_keyboard();
|
||||
modal.disable_closing();
|
||||
|
@ -311,8 +309,10 @@ impl TransportSendModal {
|
|||
let res = self.send_result.clone();
|
||||
self.sending = true;
|
||||
thread::spawn(move || {
|
||||
let runtime = TokioNativeTlsRuntime::create().unwrap();
|
||||
runtime
|
||||
tokio::runtime::Builder::new_current_thread()
|
||||
.enable_all()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block_on(async {
|
||||
let result = wallet.send_tor(a, &addr).await;
|
||||
let mut w_res = res.write();
|
||||
|
|
|
@ -339,6 +339,30 @@ impl WalletTransactions {
|
|||
DOTS_THREE_CIRCLE,
|
||||
t!("wallets.tx_sending"))
|
||||
},
|
||||
TxLogEntryType::ConfirmedCoinbase => {
|
||||
let tx_h = tx.height.unwrap_or(1) - 1;
|
||||
if tx_h != 0 {
|
||||
let left_conf = height - tx_h;
|
||||
if height >= tx_h && left_conf < COINBASE_MATURITY {
|
||||
let conf_info = format!("{}/{}",
|
||||
left_conf,
|
||||
COINBASE_MATURITY);
|
||||
format!("{} {} {}",
|
||||
DOTS_THREE_CIRCLE,
|
||||
t!("wallets.tx_confirming"),
|
||||
conf_info
|
||||
)
|
||||
} else {
|
||||
format!("{} {}",
|
||||
DOTS_THREE_CIRCLE,
|
||||
t!("wallets.tx_confirming"))
|
||||
}
|
||||
} else {
|
||||
format!("{} {}",
|
||||
DOTS_THREE_CIRCLE,
|
||||
t!("wallets.tx_confirming"))
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
format!("{} {}",
|
||||
DOTS_THREE_CIRCLE,
|
||||
|
@ -353,17 +377,20 @@ impl WalletTransactions {
|
|||
let tx_h = tx.height.unwrap_or(1) - 1;
|
||||
if tx_h != 0 {
|
||||
let left_conf = height - tx_h;
|
||||
let conf_info = if tx_h != 0 && height >= tx_h &&
|
||||
left_conf < COINBASE_MATURITY {
|
||||
format!("{}/{}", left_conf, COINBASE_MATURITY)
|
||||
if height >= tx_h && left_conf < COINBASE_MATURITY {
|
||||
let conf_info = format!("{}/{}",
|
||||
left_conf,
|
||||
COINBASE_MATURITY);
|
||||
format!("{} {} {}",
|
||||
DOTS_THREE_CIRCLE,
|
||||
t!("wallets.tx_confirming"),
|
||||
conf_info
|
||||
)
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
format!("{} {} {}",
|
||||
DOTS_THREE_CIRCLE,
|
||||
t!("wallets.tx_confirming"),
|
||||
conf_info
|
||||
)
|
||||
format!("{} {}",
|
||||
DOTS_THREE_CIRCLE,
|
||||
t!("wallets.tx_confirmed"))
|
||||
}
|
||||
} else {
|
||||
format!("{} {}",
|
||||
DOTS_THREE_CIRCLE,
|
||||
|
|
|
@ -203,6 +203,7 @@ impl WalletTransactionModal {
|
|||
if let Ok(_) = res {
|
||||
self.show_finalization = false;
|
||||
self.finalize_edit = "".to_string();
|
||||
self.response_edit = "".to_string();
|
||||
} else {
|
||||
self.finalize_error = true;
|
||||
}
|
||||
|
|
|
@ -128,7 +128,9 @@ pub fn start(options: NativeOptions, app_creator: eframe::AppCreator) -> eframe:
|
|||
/// Setup application [`egui::Style`] and [`egui::Visuals`].
|
||||
pub fn setup_visuals(ctx: &Context) {
|
||||
let use_dark = AppConfig::dark_theme().unwrap_or_else(|| {
|
||||
ctx.system_theme().unwrap_or(Theme::Dark) == Theme::Dark
|
||||
let use_dark = ctx.system_theme().unwrap_or(Theme::Dark) == Theme::Dark;
|
||||
AppConfig::set_dark_theme(use_dark);
|
||||
use_dark
|
||||
});
|
||||
|
||||
let mut style = (*ctx.style()).clone();
|
||||
|
|
25
src/main.rs
Normal file → Executable file
25
src/main.rs
Normal file → Executable file
|
@ -111,7 +111,6 @@ fn start_desktop_gui(platform: grim::gui::platform::Desktop) {
|
|||
let os = egui::os::OperatingSystem::from_target_os();
|
||||
let (width, height) = AppConfig::window_size();
|
||||
let mut viewport = egui::ViewportBuilder::default()
|
||||
|
||||
.with_min_inner_size([AppConfig::MIN_WIDTH, AppConfig::MIN_HEIGHT])
|
||||
.with_inner_size([width, height]);
|
||||
|
||||
|
@ -125,21 +124,21 @@ fn start_desktop_gui(platform: grim::gui::platform::Desktop) {
|
|||
}
|
||||
// Setup window decorations.
|
||||
let is_mac = os == egui::os::OperatingSystem::Mac;
|
||||
let is_win = os == egui::os::OperatingSystem::Windows;
|
||||
viewport = viewport
|
||||
.with_fullsize_content_view(true)
|
||||
.with_window_level(egui::WindowLevel::Normal)
|
||||
.with_title_shown(false)
|
||||
.with_titlebar_buttons_shown(false)
|
||||
.with_titlebar_shown(false)
|
||||
.with_title_shown(is_win)
|
||||
.with_titlebar_buttons_shown(is_win)
|
||||
.with_titlebar_shown(is_win)
|
||||
.with_transparent(true)
|
||||
.with_decorations(is_mac);
|
||||
.with_decorations(is_mac || is_win);
|
||||
|
||||
let mut options = eframe::NativeOptions {
|
||||
viewport,
|
||||
..Default::default()
|
||||
};
|
||||
// Use Glow renderer for Windows.
|
||||
let is_win = os == egui::os::OperatingSystem::Windows;
|
||||
options.renderer = if is_win {
|
||||
eframe::Renderer::Glow
|
||||
} else {
|
||||
|
@ -172,9 +171,10 @@ fn start_desktop_gui(platform: grim::gui::platform::Desktop) {
|
|||
#[allow(dead_code)]
|
||||
#[cfg(not(target_os = "android"))]
|
||||
fn is_app_running(data: &Option<String>) -> bool {
|
||||
use tor_rtcompat::BlockOn;
|
||||
let runtime = tor_rtcompat::tokio::TokioNativeTlsRuntime::create().unwrap();
|
||||
let res: Result<(), Box<dyn std::error::Error>> = runtime
|
||||
let res: Result<(), Box<dyn std::error::Error>> = tokio::runtime::Builder::new_current_thread()
|
||||
.enable_all()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block_on(async {
|
||||
use interprocess::local_socket::{
|
||||
tokio::{prelude::*, Stream}
|
||||
|
@ -211,9 +211,10 @@ fn is_app_running(data: &Option<String>) -> bool {
|
|||
#[cfg(not(target_os = "android"))]
|
||||
fn start_app_socket(platform: grim::gui::platform::Desktop) {
|
||||
std::thread::spawn(move || {
|
||||
use tor_rtcompat::BlockOn;
|
||||
let runtime = tor_rtcompat::tokio::TokioNativeTlsRuntime::create().unwrap();
|
||||
let _: Result<_, _> = runtime
|
||||
let _ = tokio::runtime::Builder::new_current_thread()
|
||||
.enable_all()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block_on(async {
|
||||
use interprocess::local_socket::{
|
||||
tokio::{prelude::*, Stream},
|
||||
|
|
|
@ -69,62 +69,58 @@ impl PeersConfig {
|
|||
}
|
||||
|
||||
/// Load saved peers to node server [`ConfigMembers`] config.
|
||||
pub fn load_to_server_config() {
|
||||
let mut w_config = Settings::node_config_to_update();
|
||||
pub fn load_to_server_config(config: &mut ConfigMembers) {
|
||||
// Load seeds.
|
||||
for seed in w_config.peers.seeds.clone() {
|
||||
let r_config = Settings::node_config_to_read();
|
||||
for seed in r_config.peers.seeds.clone() {
|
||||
if let Some(p) = Self::peer_to_addr(seed.to_string()) {
|
||||
let mut seeds = w_config
|
||||
.node
|
||||
let mut seeds = config
|
||||
.server
|
||||
.p2p_config
|
||||
.seeds
|
||||
.clone()
|
||||
.unwrap_or(PeerAddrs::default());
|
||||
seeds.peers.insert(seeds.peers.len(), p);
|
||||
w_config.node.server.p2p_config.seeds = Some(seeds);
|
||||
config.server.p2p_config.seeds = Some(seeds);
|
||||
}
|
||||
}
|
||||
// Load allowed peers.
|
||||
for peer in w_config.peers.allowed.clone() {
|
||||
for peer in r_config.peers.allowed.clone() {
|
||||
if let Some(p) = Self::peer_to_addr(peer.clone()) {
|
||||
let mut allowed = w_config
|
||||
.node
|
||||
let mut allowed = config
|
||||
.server
|
||||
.p2p_config
|
||||
.peers_allow
|
||||
.clone()
|
||||
.unwrap_or(PeerAddrs::default());
|
||||
allowed.peers.insert(allowed.peers.len(), p);
|
||||
w_config.node.server.p2p_config.peers_allow = Some(allowed);
|
||||
config.server.p2p_config.peers_allow = Some(allowed);
|
||||
}
|
||||
}
|
||||
// Load denied peers.
|
||||
for peer in w_config.peers.denied.clone() {
|
||||
for peer in r_config.peers.denied.clone() {
|
||||
if let Some(p) = Self::peer_to_addr(peer.clone()) {
|
||||
let mut denied = w_config
|
||||
.node
|
||||
let mut denied = config
|
||||
.server
|
||||
.p2p_config
|
||||
.peers_deny
|
||||
.clone()
|
||||
.unwrap_or(PeerAddrs::default());
|
||||
denied.peers.insert(denied.peers.len(), p);
|
||||
w_config.node.server.p2p_config.peers_deny = Some(denied);
|
||||
config.server.p2p_config.peers_deny = Some(denied);
|
||||
}
|
||||
}
|
||||
// Load preferred peers.
|
||||
for peer in &w_config.peers.preferred.clone() {
|
||||
for peer in &r_config.peers.preferred.clone() {
|
||||
if let Some(p) = Self::peer_to_addr(peer.clone()) {
|
||||
let mut preferred = w_config
|
||||
.node
|
||||
let mut preferred = config
|
||||
.server
|
||||
.p2p_config
|
||||
.peers_preferred
|
||||
.clone()
|
||||
.unwrap_or(PeerAddrs::default());
|
||||
preferred.peers.insert(preferred.peers.len(), p);
|
||||
w_config.node.server.p2p_config.peers_preferred = Some(preferred);
|
||||
config.server.p2p_config.peers_preferred = Some(preferred);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -194,13 +190,13 @@ impl NodeConfig {
|
|||
fn setup_default_ports(config: &mut ConfigMembers) {
|
||||
let (api, p2p) = match config.server.chain_type {
|
||||
ChainTypes::Mainnet => {
|
||||
let api = rand::thread_rng().gen_range(30000..33000);
|
||||
let p2p = rand::thread_rng().gen_range(33000..37000);
|
||||
let api = rand::rng().random_range(30000..33000);
|
||||
let p2p = rand::rng().random_range(33000..37000);
|
||||
(api, p2p)
|
||||
},
|
||||
_ => {
|
||||
let api = rand::thread_rng().gen_range(40000..43000);
|
||||
let p2p = rand::thread_rng().gen_range(43000..47000);
|
||||
let api = rand::rng().random_range(40000..43000);
|
||||
let p2p = rand::rng().random_range(43000..47000);
|
||||
(api, p2p)
|
||||
}
|
||||
};
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
//! them into a block and returns it.
|
||||
|
||||
use chrono::prelude::{DateTime, Utc};
|
||||
use rand::{thread_rng, Rng};
|
||||
use rand::{rng, Rng};
|
||||
use serde_json::{json, Value};
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
|
@ -174,7 +174,7 @@ fn build_block(
|
|||
// making sure we're not spending time mining a useless block
|
||||
b.validate(&head.total_kernel_offset)?;
|
||||
|
||||
b.header.pow.nonce = thread_rng().gen();
|
||||
b.header.pow.nonce = rng().random();
|
||||
b.header.pow.secondary_scaling = difficulty.secondary_scaling;
|
||||
b.header.timestamp = DateTime::from_timestamp(now_sec, 0).unwrap();
|
||||
|
||||
|
|
|
@ -366,15 +366,6 @@ impl Node {
|
|||
}
|
||||
let config = NodeConfig::node_server_config();
|
||||
let server_config = config.server.clone();
|
||||
|
||||
// Remove lock file if exists.
|
||||
let mut lock_path = PathBuf::from(&server_config.db_root);
|
||||
lock_path.push("grin.lock");
|
||||
if lock_path.exists() {
|
||||
fs::remove_file(lock_path).unwrap();
|
||||
}
|
||||
|
||||
// Remove chain data.
|
||||
let dirs_to_remove: Vec<&str> = vec!["header", "lmdb", "txhashset"];
|
||||
for dir in dirs_to_remove {
|
||||
let mut path = PathBuf::from(&server_config.db_root);
|
||||
|
@ -529,8 +520,8 @@ impl Node {
|
|||
/// Start the node [`Server`].
|
||||
fn start_node_server() -> Result<Server, Error> {
|
||||
// Setup server config.
|
||||
PeersConfig::load_to_server_config();
|
||||
let config = NodeConfig::node_server_config();
|
||||
let mut config = NodeConfig::node_server_config();
|
||||
PeersConfig::load_to_server_config(&mut config);
|
||||
let mut server_config = config.server.clone();
|
||||
|
||||
// Setup Mainnet DNSSeed
|
||||
|
|
|
@ -31,6 +31,7 @@ use grin_util::secp::SecretKey;
|
|||
use hyper::{Body, Uri};
|
||||
use parking_lot::RwLock;
|
||||
use sha2::Sha512;
|
||||
use tls_api_native_tls::TlsConnector;
|
||||
use tls_api::{TlsConnector as TlsConnectorTrait, TlsConnectorBuilder};
|
||||
use tokio::time::sleep;
|
||||
use tor_hscrypto::pk::{HsIdKey, HsIdKeypair};
|
||||
|
@ -47,14 +48,6 @@ use tor_llcrypto::pk::ed25519::ExpandedKeypair;
|
|||
use tor_rtcompat::tokio::TokioNativeTlsRuntime;
|
||||
use tor_rtcompat::Runtime;
|
||||
|
||||
// On aarch64-apple-darwin targets there is an issue with the native and rustls
|
||||
// tls implementation so this makes it fall back to the openssl variant.
|
||||
//
|
||||
// https://gitlab.torproject.org/tpo/core/arti/-/issues/715
|
||||
#[cfg(not(all(target_vendor = "apple", target_arch = "aarch64")))]
|
||||
use tls_api_native_tls::TlsConnector;
|
||||
#[cfg(all(target_vendor = "apple", target_arch = "aarch64"))]
|
||||
use tls_api_openssl::TlsConnector;
|
||||
use crate::tor::http::ArtiHttpConnector;
|
||||
use crate::tor::TorConfig;
|
||||
|
||||
|
@ -80,20 +73,16 @@ pub struct Tor {
|
|||
|
||||
impl Default for Tor {
|
||||
fn default() -> Self {
|
||||
// Cleanup keys, state and cache on start.
|
||||
fs::remove_dir_all(TorConfig::keystore_path()).unwrap_or_default();
|
||||
fs::remove_dir_all(TorConfig::state_path()).unwrap_or_default();
|
||||
fs::remove_dir_all(TorConfig::cache_path()).unwrap_or_default();
|
||||
// Create Tor client.
|
||||
let runtime = TokioNativeTlsRuntime::create().unwrap();
|
||||
let config = Self::build_config();
|
||||
let client = if let Ok(c) = TorClient::with_runtime(runtime)
|
||||
let client = TorClient::with_runtime(runtime)
|
||||
.config(config.clone())
|
||||
.create_unbootstrapped() {
|
||||
c
|
||||
} else {
|
||||
fs::remove_dir_all(TorConfig::state_path()).unwrap();
|
||||
fs::remove_dir_all(TorConfig::cache_path()).unwrap();
|
||||
let runtime = TokioNativeTlsRuntime::create().unwrap();
|
||||
TorClient::with_runtime(runtime)
|
||||
.config(config.clone())
|
||||
.create_unbootstrapped().unwrap()
|
||||
};
|
||||
.create_unbootstrapped().unwrap();
|
||||
Self {
|
||||
running_services: Arc::new(RwLock::new(BTreeMap::new())),
|
||||
starting_services: Arc::new(RwLock::new(BTreeSet::new())),
|
||||
|
@ -274,7 +263,8 @@ impl Tor {
|
|||
return;
|
||||
}
|
||||
let client_check = client_thread.clone();
|
||||
let url = format!("http://{}/", service.onion_name().unwrap().to_string());
|
||||
let addr = service.onion_address().unwrap().to_string();
|
||||
let url = format!("http://{}/", addr);
|
||||
thread::spawn(move || {
|
||||
// Wait 1 second to start.
|
||||
thread::sleep(Duration::from_millis(1000));
|
||||
|
@ -313,6 +303,10 @@ impl Tor {
|
|||
let mut w_services =
|
||||
TOR_SERVER_STATE.starting_services.write();
|
||||
w_services.remove(&service_id);
|
||||
// Remove service from failed.
|
||||
let mut w_services =
|
||||
TOR_SERVER_STATE.failed_services.write();
|
||||
w_services.remove(&service_id);
|
||||
// Check again after 50 seconds.
|
||||
Duration::from_millis(50000)
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ impl WalletConfig {
|
|||
min_confirmations: MIN_CONFIRMATIONS_DEFAULT,
|
||||
use_dandelion: Some(true),
|
||||
enable_tor_listener: Some(false),
|
||||
api_port: Some(rand::thread_rng().gen_range(10000..30000)),
|
||||
api_port: Some(rand::rng().random_range(10000..30000)),
|
||||
};
|
||||
Settings::write_to_file(&config, config_path);
|
||||
config
|
||||
|
@ -121,9 +121,7 @@ impl WalletConfig {
|
|||
pub fn connection(&self) -> ConnectionMethod {
|
||||
if let Some(ext_conn_id) = self.ext_conn_id {
|
||||
if let Some(conn) = ConnectionsConfig::ext_conn(ext_conn_id) {
|
||||
if !conn.deleted {
|
||||
return ConnectionMethod::External(conn.id, conn.url);
|
||||
}
|
||||
return ConnectionMethod::External(conn.id, conn.url);
|
||||
}
|
||||
}
|
||||
ConnectionMethod::Integrated
|
||||
|
|
|
@ -49,13 +49,7 @@ impl ConnectionsConfig {
|
|||
|
||||
/// Save connections configuration.
|
||||
pub fn save(&mut self) {
|
||||
// Check deleted external connections.
|
||||
let mut config = self.clone();
|
||||
config.external = config.external.iter()
|
||||
.map(|c| c.clone())
|
||||
.filter(|c| !c.deleted)
|
||||
.collect::<Vec<ExternalConnection>>();
|
||||
|
||||
let config = self.clone();
|
||||
let sub_dir = Some(AppConfig::chain_type().shortname());
|
||||
Settings::write_to_file(&config, Settings::config_path(Self::FILE_NAME, sub_dir));
|
||||
}
|
||||
|
@ -106,13 +100,7 @@ impl ConnectionsConfig {
|
|||
/// Remove [`ExternalConnection`] with provided identifier.
|
||||
pub fn remove_ext_conn(id: i64) {
|
||||
let mut w_config = Settings::conn_config_to_update();
|
||||
if let Some(pos) = w_config.external.iter().position(|c| {
|
||||
c.id == id
|
||||
}) {
|
||||
if let Some(conn) = w_config.external.get_mut(pos) {
|
||||
conn.deleted = true;
|
||||
w_config.save();
|
||||
}
|
||||
}
|
||||
w_config.external = w_config.external.iter().filter(|c| c.id != id).cloned().collect();
|
||||
w_config.save();
|
||||
}
|
||||
}
|
|
@ -31,10 +31,6 @@ pub struct ExternalConnection {
|
|||
/// Flag to check if server is available.
|
||||
#[serde(skip_serializing, skip_deserializing)]
|
||||
pub available: Option<bool>,
|
||||
|
||||
/// Flag to check if connection was deleted.
|
||||
#[serde(skip_serializing, skip_deserializing)]
|
||||
pub deleted: bool
|
||||
}
|
||||
|
||||
/// Default external node URL for main network.
|
||||
|
@ -61,7 +57,6 @@ impl ExternalConnection {
|
|||
url: url.to_string(),
|
||||
secret: None,
|
||||
available: None,
|
||||
deleted: false,
|
||||
}
|
||||
}).collect::<Vec<ExternalConnection>>()
|
||||
}
|
||||
|
@ -74,11 +69,10 @@ impl ExternalConnection {
|
|||
url,
|
||||
secret,
|
||||
available: None,
|
||||
deleted: false
|
||||
}
|
||||
}
|
||||
|
||||
/// Check external connections availability.
|
||||
/// Check external connection availability.
|
||||
pub fn check(id: Option<i64>, ui_ctx: &egui::Context) {
|
||||
let conn_list = ConnectionsConfig::ext_conn_list();
|
||||
for conn in conn_list {
|
||||
|
@ -99,7 +93,7 @@ fn check_ext_conn(conn: &ExternalConnection, ui_ctx: &egui::Context) {
|
|||
let ui_ctx = ui_ctx.clone();
|
||||
ConnectionsConfig::update_ext_conn_status(conn.id, None);
|
||||
std::thread::spawn(move || {
|
||||
tokio::runtime::Builder::new_multi_thread()
|
||||
tokio::runtime::Builder::new_current_thread()
|
||||
.enable_all()
|
||||
.build()
|
||||
.unwrap()
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
use grin_keychain::mnemonic::{from_entropy, search, to_entropy};
|
||||
use grin_util::ZeroingString;
|
||||
use rand::{Rng, thread_rng};
|
||||
use rand::Rng;
|
||||
|
||||
use crate::wallet::types::{PhraseMode, PhraseSize, PhraseWord};
|
||||
|
||||
|
@ -100,10 +100,10 @@ impl Mnemonic {
|
|||
fn generate_words(mode: &PhraseMode, size: &PhraseSize) -> Vec<PhraseWord> {
|
||||
match mode {
|
||||
PhraseMode::Generate => {
|
||||
let mut rng = thread_rng();
|
||||
let mut rng = rand::rng();
|
||||
let mut entropy: Vec<u8> = Vec::with_capacity(size.entropy_size());
|
||||
for _ in 0..size.entropy_size() {
|
||||
entropy.push(rng.gen());
|
||||
entropy.push(rng.random());
|
||||
}
|
||||
from_entropy(&entropy).unwrap()
|
||||
.split(" ")
|
||||
|
|
|
@ -617,7 +617,7 @@ impl Wallet {
|
|||
let r_inst = self.instance.as_ref().read();
|
||||
let instance = r_inst.clone().unwrap();
|
||||
let mut api = Owner::new(instance, None);
|
||||
return match parse_slatepack(&mut api, None, None, Some(text.clone())) {
|
||||
match parse_slatepack(&mut api, None, None, Some(text.clone())) {
|
||||
Ok(s) => Ok(s.0),
|
||||
Err(e) => Err(e)
|
||||
}
|
||||
|
@ -714,7 +714,7 @@ impl Wallet {
|
|||
amount,
|
||||
minimum_confirmations: config.min_confirmations,
|
||||
num_change_outputs: 1,
|
||||
selection_strategy_is_use_all: true,
|
||||
selection_strategy_is_use_all: false,
|
||||
..Default::default()
|
||||
};
|
||||
let r_inst = self.instance.as_ref().read();
|
||||
|
@ -857,7 +857,7 @@ impl Wallet {
|
|||
src_acct_name: None,
|
||||
amount: slate.amount,
|
||||
minimum_confirmations: config.min_confirmations,
|
||||
selection_strategy_is_use_all: true,
|
||||
selection_strategy_is_use_all: false,
|
||||
..Default::default()
|
||||
};
|
||||
let r_inst = self.instance.as_ref().read();
|
||||
|
@ -1415,7 +1415,7 @@ fn sync_wallet_data(wallet: &Wallet, from_node: bool) {
|
|||
/// Start Foreign API server to receive txs over transport and mining rewards.
|
||||
fn start_api_server(wallet: &Wallet) -> Result<(ApiServer, u16), Error> {
|
||||
let host = "127.0.0.1";
|
||||
let port = wallet.get_config().api_port.unwrap_or(rand::thread_rng().gen_range(10000..30000));
|
||||
let port = wallet.get_config().api_port.unwrap_or(rand::rng().random_range(10000..30000));
|
||||
let free_port = (port..).find(|port| {
|
||||
return match TcpListener::bind((host, port.to_owned())) {
|
||||
Ok(_) => {
|
||||
|
|
|
@ -7,14 +7,11 @@
|
|||
<?endif ?>
|
||||
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||
<Product Id="*" UpgradeCode="C19F9B41-CD13-4F0E-B27D-E0EF8CF1CE91" Version="0.1.0" Language="1033" Name="Grim" Manufacturer="Ardocrat">
|
||||
<Package Id="7a18ee67-b049-4462-b18f-9e7748685781" InstallerVersion="300" Compressed="yes"/>
|
||||
<Product Id="*" Version="0.2.4" UpgradeCode="C19F9B41-CD13-4F0E-B27D-E0EF8CF1CE91" Language="1033" Name="Grim" Manufacturer="Ardocrat">
|
||||
<Package Id="FA6823B7-7FB1-49A4-BF64-0442BCD2724B" InstallerVersion="300" Compressed="yes"/>
|
||||
<Media Id="1" Cabinet="grim.cab" EmbedCab="yes" />
|
||||
|
||||
<MajorUpgrade
|
||||
DowngradeErrorMessage = "A newer version of [ProductName] is already installed."
|
||||
AllowSameVersionUpgrades = "yes"
|
||||
/>
|
||||
<MajorUpgrade AllowDowngrades = "yes"/>
|
||||
|
||||
<Icon Id='Product.ico' SourceFile='wix\Product.ico'/>
|
||||
<Property Id='ARPPRODUCTICON' Value='Product.ico' />
|
||||
|
|
Loading…
Add table
Reference in a new issue