From 8b5ab593effb4997b233e1aab06a1140388dc591 Mon Sep 17 00:00:00 2001 From: cipig Date: Mon, 27 Jul 2020 11:27:29 +0000 Subject: [PATCH 001/515] transparent bg for ILN --- atomic_qt_design/assets/images/coins/iln.png | Bin 10062 -> 134761 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/atomic_qt_design/assets/images/coins/iln.png b/atomic_qt_design/assets/images/coins/iln.png index 4b69d921067df668ef2293063d487363f8bcb1ab..0090ce7623295ec941ea2bfb7c38c700e55d1311 100644 GIT binary patch literal 134761 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

0tj?ZJ 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 From 1a813dbf575c066fafe8f64a417f4e3750f0a76c Mon Sep 17 00:00:00 2001 From: Roman Sztergbaum Date: Tue, 28 Jul 2020 11:21:59 +0200 Subject: [PATCH 002/515] fix(orders): dissapear / removal --- src/atomic.dex.qt.orders.model.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/atomic.dex.qt.orders.model.cpp b/src/atomic.dex.qt.orders.model.cpp index 78207add25..406298458b 100644 --- a/src/atomic.dex.qt.orders.model.cpp +++ b/src/atomic.dex.qt.orders.model.cpp @@ -434,14 +434,17 @@ namespace atomic_dex if (not res_list.empty()) { //! And then delete it + spdlog::trace("removing order with id {} from the UI", id); this->removeRow(res_list.at(0).row()); to_remove.emplace(id); } } } - std::unordered_set out; - std::set_difference(begin(m_orders_id_registry), end(m_orders_id_registry), begin(to_remove), end(to_remove), std::inserter(out, out.begin())); - m_orders_id_registry = out; + //std::unordered_set out; + //std::set_difference(begin(m_orders_id_registry), end(m_orders_id_registry), begin(to_remove), end(to_remove), std::inserter(out, out.begin())); + for (auto&& cur_to_remove : to_remove) { + m_orders_id_registry.erase(cur_to_remove); + } } } From 3c96c5f7ef134654f3881ac01b94c8bf1b86541e Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 28 Jul 2020 14:01:34 +0300 Subject: [PATCH 003/515] feat(gui): use an alternative bitcoin symbol for linux --- atomic_qt_design/qml/Constants/General.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomic_qt_design/qml/Constants/General.qml b/atomic_qt_design/qml/Constants/General.qml index ac770af3b5..11abfcdbfc 100644 --- a/atomic_qt_design/qml/Constants/General.qml +++ b/atomic_qt_design/qml/Constants/General.qml @@ -100,7 +100,7 @@ QtObject { const symbols = { "USD": "$", "EUR": "€", - "BTC": "₿", + "BTC": Qt.platform.os === 'linux' ? "฿" : "₿", "KMD": "KMD", } From 3d80b39673994f652ac9cf04693c5212fd9c0941 Mon Sep 17 00:00:00 2001 From: milerius Date: Tue, 28 Jul 2020 13:35:05 +0200 Subject: [PATCH 004/515] feat(orderbook): starting revamp of orderbook part --- CMakeLists.txt | 2 ++ src/atomic.dex.app.cpp | 20 -------------------- src/atomic.dex.app.hpp | 2 -- src/atomic.dex.qt.orderbook.cpp | 22 ++++++++++++++++++++++ src/atomic.dex.qt.orderbook.hpp | 22 ++++++++++++++++++++++ src/atomic.dex.qt.orderbook.model.cpp | 22 ++++++++++++++++++++++ src/atomic.dex.qt.orderbook.model.hpp | 22 ++++++++++++++++++++++ 7 files changed, 90 insertions(+), 22 deletions(-) create mode 100644 src/atomic.dex.qt.orderbook.cpp create mode 100644 src/atomic.dex.qt.orderbook.hpp create mode 100644 src/atomic.dex.qt.orderbook.model.cpp create mode 100644 src/atomic.dex.qt.orderbook.model.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ef9b68da33..14a93cc132 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -160,6 +160,8 @@ target_sources(atomic_qt_shared_deps INTERFACE ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.addressbook.model.cpp ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.addressbook.proxy.filter.model.cpp ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.contact.model.cpp + ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.orderbook.cpp + ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.orderbook.model.cpp ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.portfolio.model.cpp ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.portfolio.proxy.filter.model.cpp $<$:${CMAKE_SOURCE_DIR}/src/osx/atomic.dex.osx.manager.mm> diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index fc9bd61f40..044e48a951 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -1249,18 +1249,6 @@ namespace atomic_dex return m_candlestick_chart_ohlc; } - QVariantList - application::get_ohlc_data(const QString& range) - { - QVariantList out; - auto& provider = this->system_manager_.get_system(); - auto json = provider.get_ohlc_data(range.toStdString()); - - QJsonDocument q_json = QJsonDocument::fromJson(QString::fromStdString(json.dump()).toUtf8()); - out = q_json.array().toVariantList(); - return out; - } - QVariantMap application::find_closest_ohlc_data(int range, int timestamp) { @@ -1281,14 +1269,6 @@ namespace atomic_dex return out; } - bool - application::is_supported_ohlc_data_ticker_pair(const QString& base, const QString& rel) - { - auto& provider = this->system_manager_.get_system(); - auto [normal, quoted] = provider.is_pair_supported(base.toStdString(), rel.toStdString()); - return normal || quoted; - } - void application::on_refresh_ohlc_event([[maybe_unused]] const refresh_ohlc_needed& evt) noexcept { diff --git a/src/atomic.dex.app.hpp b/src/atomic.dex.app.hpp index b722c4bc52..8c2359ec95 100644 --- a/src/atomic.dex.app.hpp +++ b/src/atomic.dex.app.hpp @@ -212,9 +212,7 @@ namespace atomic_dex Q_INVOKABLE QString get_cex_rates(const QString& base, const QString& rel); Q_INVOKABLE QString get_fiat_from_amount(const QString& ticker, const QString& amount); - Q_INVOKABLE QVariantList get_ohlc_data(const QString& range); Q_INVOKABLE QVariantMap find_closest_ohlc_data(int range, int timestamp); - Q_INVOKABLE bool is_supported_ohlc_data_ticker_pair(const QString& base, const QString& rel); Q_INVOKABLE QVariant get_coin_info(const QString& ticker); Q_INVOKABLE bool export_swaps(const QString& csv_filename) noexcept; Q_INVOKABLE bool export_swaps_json() noexcept; diff --git a/src/atomic.dex.qt.orderbook.cpp b/src/atomic.dex.qt.orderbook.cpp new file mode 100644 index 0000000000..f98f7f4cbe --- /dev/null +++ b/src/atomic.dex.qt.orderbook.cpp @@ -0,0 +1,22 @@ +/****************************************************************************** + * Copyright © 2013-2019 The Komodo Platform Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * Komodo Platform software, including this file may be copied, modified, * + * propagated or distributed except according to the terms contained in the * + * LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + +#include "atomic.dex.qt.orderbook.hpp" + +namespace atomic_dex +{ + +} \ No newline at end of file diff --git a/src/atomic.dex.qt.orderbook.hpp b/src/atomic.dex.qt.orderbook.hpp new file mode 100644 index 0000000000..083459185d --- /dev/null +++ b/src/atomic.dex.qt.orderbook.hpp @@ -0,0 +1,22 @@ +/****************************************************************************** + * Copyright © 2013-2019 The Komodo Platform Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * Komodo Platform software, including this file may be copied, modified, * + * propagated or distributed except according to the terms contained in the * + * LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + +#pragma once + +namespace atomic_dex +{ + +} \ No newline at end of file diff --git a/src/atomic.dex.qt.orderbook.model.cpp b/src/atomic.dex.qt.orderbook.model.cpp new file mode 100644 index 0000000000..f2e3f8349d --- /dev/null +++ b/src/atomic.dex.qt.orderbook.model.cpp @@ -0,0 +1,22 @@ +/****************************************************************************** + * Copyright © 2013-2019 The Komodo Platform Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * Komodo Platform software, including this file may be copied, modified, * + * propagated or distributed except according to the terms contained in the * + * LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + +#include "atomic.dex.qt.orderbook.model.hpp" + +namespace atomic_dex +{ + +} \ No newline at end of file diff --git a/src/atomic.dex.qt.orderbook.model.hpp b/src/atomic.dex.qt.orderbook.model.hpp new file mode 100644 index 0000000000..083459185d --- /dev/null +++ b/src/atomic.dex.qt.orderbook.model.hpp @@ -0,0 +1,22 @@ +/****************************************************************************** + * Copyright © 2013-2019 The Komodo Platform Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * Komodo Platform software, including this file may be copied, modified, * + * propagated or distributed except according to the terms contained in the * + * LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + +#pragma once + +namespace atomic_dex +{ + +} \ No newline at end of file From 39e8a3c4ce04a14f10fa807ba68cd86e75856336 Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 28 Jul 2020 14:38:01 +0300 Subject: [PATCH 005/515] feat(gui): remove unused api func --- atomic_qt_design/qml/Constants/API.qml | 2 -- 1 file changed, 2 deletions(-) diff --git a/atomic_qt_design/qml/Constants/API.qml b/atomic_qt_design/qml/Constants/API.qml index 23a307e776..58691eb740 100644 --- a/atomic_qt_design/qml/Constants/API.qml +++ b/atomic_qt_design/qml/Constants/API.qml @@ -291,8 +291,6 @@ QtObject { find_closest_ohlc_data: () => { return {"close":0.0000654,"high":0.0000655,"low":0.0000654,"open":0.0000655,"quote_volume":0.006986865,"timestamp":1593740820,"volume":106.83} }, - get_ohlc_data: (range) => [{"close":0.0000654,"high":0.0000655,"low":0.0000654,"open":0.0000655,"quote_volume":0.006986865,"timestamp":1593740820,"volume":106.83},{"close":0.0000653,"high":0.0000653,"low":0.0000653,"open":0.0000653,"quote_volume":0.0068565,"timestamp":1593740880,"volume":105},{"close":0.0000653,"high":0.0000653,"low":0.0000653,"open":0.0000653,"quote_volume":0.007420692,"timestamp":1593741000,"volume":113.64}], - get_wallets: () => { return ["naezith", "slyris", "ca333", "tony"] }, get_trade_infos: (ticker, receive_ticker, amount) => { From 5b29de749b1e61633b23d20db8e71056e9dda2b6 Mon Sep 17 00:00:00 2001 From: milerius Date: Tue, 28 Jul 2020 13:50:01 +0200 Subject: [PATCH 006/515] feat(orderbook): connect orderbook wrapper to the backend --- src/atomic.dex.app.cpp | 12 +++++++++++- src/atomic.dex.app.hpp | 10 +++++++--- src/atomic.dex.qt.orderbook.cpp | 12 +++++++++++- src/atomic.dex.qt.orderbook.hpp | 17 ++++++++++++++++- 4 files changed, 45 insertions(+), 6 deletions(-) diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index 044e48a951..59924e2f86 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -405,7 +405,7 @@ namespace atomic_dex {"update_needed", false}, {"changelog", ""}, {"current_version", ""}, {"download_url", ""}, {"new_version", ""}, {"rpc_code", 0}, {"status", ""}}), m_coin_info(new current_coin_info(dispatcher_, this)), m_addressbook(new addressbook_model(this->m_wallet_manager, this)), m_portfolio(new portfolio_model(this->system_manager_, this->m_config, this)), m_orders(new orders_model(this->system_manager_, this)), - m_candlestick_chart_ohlc(new candlestick_charts_model(this->system_manager_, this)) + m_candlestick_chart_ohlc(new candlestick_charts_model(this->system_manager_, this)), m_orderbook(new qt_orderbook_wrapper(this->system_manager_, this)) { get_dispatcher().sink().connect<&application::on_refresh_update_status_event>(*this); //! MM2 system need to be created before the GUI and give the instance to the gui @@ -1470,4 +1470,14 @@ namespace atomic_dex { this->m_candlestick_chart_ohlc->set_is_currently_fetching(evt.is_a_reset); } +} // namespace atomic_dex + +//! Orderbook +namespace atomic_dex +{ + qt_orderbook_wrapper* + application::get_orderbook_wrapper() const noexcept + { + return m_orderbook; + } } // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.app.hpp b/src/atomic.dex.app.hpp index 8c2359ec95..406f1b1277 100644 --- a/src/atomic.dex.app.hpp +++ b/src/atomic.dex.app.hpp @@ -39,6 +39,7 @@ #include "atomic.dex.qt.orders.model.hpp" #include "atomic.dex.qt.portfolio.model.hpp" #include "atomic.dex.qt.wallet.manager.hpp" +#include "atomic.dex.qt.orderbook.hpp" namespace ag = antara::gaming; @@ -57,6 +58,7 @@ namespace atomic_dex Q_PROPERTY(QObject* current_coin_info READ get_current_coin_info NOTIFY coinInfoChanged) Q_PROPERTY(addressbook_model* addressbook_mdl READ get_addressbook NOTIFY addressbookChanged) Q_PROPERTY(orders_model* orders_mdl READ get_orders NOTIFY ordersChanged) + Q_PROPERTY(qt_orderbook_wrapper* orderbook READ get_orderbook_wrapper NOTIFY orderbookChanged) Q_PROPERTY(candlestick_charts_model* candlestick_charts_mdl READ get_candlestick_charts NOTIFY candlestickChartsChanged) Q_PROPERTY(QVariant update_status READ get_update_status NOTIFY updateStatusChanged) Q_PROPERTY(portfolio_model* portfolio_mdl READ get_portfolio NOTIFY portfolioChanged) @@ -122,7 +124,7 @@ namespace atomic_dex portfolio_model* get_portfolio() const noexcept; orders_model* get_orders() const noexcept; candlestick_charts_model* get_candlestick_charts() const noexcept; - ; + qt_orderbook_wrapper* get_orderbook_wrapper() const noexcept; QVariantList get_enabled_coins() const noexcept; QVariantList get_enableable_coins() const noexcept; QString get_current_currency() const noexcept; @@ -211,7 +213,6 @@ namespace atomic_dex Q_INVOKABLE QString get_cex_rates(const QString& base, const QString& rel); Q_INVOKABLE QString get_fiat_from_amount(const QString& ticker, const QString& amount); - Q_INVOKABLE QVariantMap find_closest_ohlc_data(int range, int timestamp); Q_INVOKABLE QVariant get_coin_info(const QString& ticker); Q_INVOKABLE bool export_swaps(const QString& csv_filename) noexcept; @@ -241,9 +242,9 @@ namespace atomic_dex void updateStatusChanged(); void ordersChanged(); void candlestickChartsChanged(); + void orderbookChanged(); public slots: void exit_handler(); - ; private: void process_refresh_enabled_coin_action(); @@ -288,6 +289,9 @@ namespace atomic_dex candlestick_charts_model* m_candlestick_chart_ohlc; std::atomic_bool m_candlestick_need_a_reset{false}; + //! Orderbook Model Wrapper + qt_orderbook_wrapper* m_orderbook; + std::atomic_bool m_about_to_exit_app{false}; }; } // namespace atomic_dex diff --git a/src/atomic.dex.qt.orderbook.cpp b/src/atomic.dex.qt.orderbook.cpp index f98f7f4cbe..1a1ee9d8c1 100644 --- a/src/atomic.dex.qt.orderbook.cpp +++ b/src/atomic.dex.qt.orderbook.cpp @@ -18,5 +18,15 @@ namespace atomic_dex { + qt_orderbook_wrapper::qt_orderbook_wrapper(ag::ecs::system_manager& system_manager, QObject* parent) : QObject(parent), m_system_manager(system_manager) + { + spdlog::trace("{} l{} f[{}]", __FUNCTION__, __LINE__, fs::path(__FILE__).filename().string()); + spdlog::trace("orderbook wrapper object created"); + } -} \ No newline at end of file + qt_orderbook_wrapper::~qt_orderbook_wrapper() noexcept + { + spdlog::trace("{} l{} f[{}]", __FUNCTION__, __LINE__, fs::path(__FILE__).filename().string()); + spdlog::trace("orderbook wrapper object destroyed"); + } +} // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.orderbook.hpp b/src/atomic.dex.qt.orderbook.hpp index 083459185d..2847601b64 100644 --- a/src/atomic.dex.qt.orderbook.hpp +++ b/src/atomic.dex.qt.orderbook.hpp @@ -16,7 +16,22 @@ #pragma once +//! QT +#include + +//! PCH +#include "atomic.dex.pch.hpp" + namespace atomic_dex { + class qt_orderbook_wrapper final : public QObject + { + Q_OBJECT + public: + qt_orderbook_wrapper(ag::ecs::system_manager& system_manager, QObject* parent = nullptr); + ~qt_orderbook_wrapper() noexcept final; -} \ No newline at end of file + private: + ag::ecs::system_manager& m_system_manager; + }; +} // namespace atomic_dex \ No newline at end of file From a3740ab904e55229b50e514ec2d30e5711da3ad7 Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 28 Jul 2020 15:00:00 +0300 Subject: [PATCH 007/515] feat(gui): privacy for dex coins list balance --- atomic_qt_design/qml/Components/DefaultText.qml | 2 +- atomic_qt_design/qml/Constants/General.qml | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/Components/DefaultText.qml b/atomic_qt_design/qml/Components/DefaultText.qml index 72be9cbc2d..a19f6a31aa 100644 --- a/atomic_qt_design/qml/Components/DefaultText.qml +++ b/atomic_qt_design/qml/Components/DefaultText.qml @@ -11,7 +11,7 @@ Text { font.family: Style.font_family font.pixelSize: Style.textSize color: Style.colorText - text: privacy && General.privacy_mode ? "*****" : text_value + text: privacy && General.privacy_mode ? General.privacy_text : text_value wrapMode: Text.WordWrap } diff --git a/atomic_qt_design/qml/Constants/General.qml b/atomic_qt_design/qml/Constants/General.qml index 11abfcdbfc..23e2a25a78 100644 --- a/atomic_qt_design/qml/Constants/General.qml +++ b/atomic_qt_design/qml/Constants/General.qml @@ -16,6 +16,7 @@ QtObject { readonly property string cex_icon: 'ⓘ' readonly property string download_icon: '📥' readonly property string right_arrow_icon: "⮕" + readonly property string privacy_text: "*****" property bool privacy_mode: false @@ -165,8 +166,10 @@ QtObject { } function getTickersAndBalances(coins) { + const privacy_on = General.privacy_mode + const privacy_text = General.privacy_text return coins.map(c => { - return { value: c.ticker, text: c.ticker + " (" + c.balance + ")" } + return { value: c.ticker, text: c.ticker + " (" + (privacy_on ? privacy_text : c.balance) + ")" } }) } From 3e7c41992833a6a1d3bf36a3d3082fed330dc477 Mon Sep 17 00:00:00 2001 From: milerius Date: Tue, 28 Jul 2020 14:16:57 +0200 Subject: [PATCH 008/515] feat(orderbook): remove old usage of the orderbook --- src/atomic.dex.app.cpp | 29 ----------- src/atomic.dex.app.hpp | 1 - src/atomic.dex.mm2.cpp | 63 ++++++++---------------- src/atomic.dex.mm2.hpp | 31 ++++++------ src/atomic.dex.qt.bindings.cpp | 2 - src/atomic.dex.qt.bindings.hpp | 88 ---------------------------------- 6 files changed, 37 insertions(+), 177 deletions(-) diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index 59924e2f86..6a9949f829 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -760,35 +760,6 @@ namespace atomic_dex this->dispatcher_.trigger(base.toStdString(), rel.toStdString()); } - QVariantMap - application::get_orderbook(const QString& ticker) - { - QVariantMap out; - std::error_code ec; - auto answer = get_mm2().get_orderbook(ticker.toStdString(), ec); - if (ec == dextop_error::orderbook_ticker_not_found) - { - spdlog::warn("{}", ec.message()); - return out; - } - for (auto&& current_orderbook: answer) - { - nlohmann::json j_out = nlohmann::json::array(); - for (auto&& current_bid: current_orderbook.bids) - { - nlohmann::json current_j_bid = { - {"volume", current_bid.maxvolume}, - {"price", current_bid.price}, - {"price_denom", current_bid.price_fraction_denom}, - {"price_numer", current_bid.price_fraction_numer}}; - j_out.push_back(current_j_bid); - } - auto out_orderbook = QJsonDocument::fromJson(QString::fromStdString(j_out.dump()).toUtf8()); - out.insert(QString::fromStdString(current_orderbook.rel), out_orderbook.toVariant()); - } - return out; - } - void application::on_refresh_update_status_event([[maybe_unused]] const refresh_update_status& evt) noexcept { diff --git a/src/atomic.dex.app.hpp b/src/atomic.dex.app.hpp index 406f1b1277..b542d208c7 100644 --- a/src/atomic.dex.app.hpp +++ b/src/atomic.dex.app.hpp @@ -204,7 +204,6 @@ namespace atomic_dex const QString& base, const QString& rel, const QString& price, const QString& volume, bool is_created_order, const QString& price_denom, const QString& price_numer); Q_INVOKABLE void set_current_orderbook(const QString& base, const QString& rel); - Q_INVOKABLE QVariantMap get_orderbook(const QString& ticker); Q_INVOKABLE bool do_i_have_enough_funds(const QString& ticker, const QString& amount) const; Q_INVOKABLE bool disable_coins(const QStringList& coins); Q_INVOKABLE bool is_claiming_ready(const QString& ticker); diff --git a/src/atomic.dex.mm2.cpp b/src/atomic.dex.mm2.cpp index 161f614c25..02feac00ee 100644 --- a/src/atomic.dex.mm2.cpp +++ b/src/atomic.dex.mm2.cpp @@ -487,48 +487,38 @@ namespace atomic_dex return m_coins_informations.at(ticker); } - std::vector - mm2::get_orderbook(const std::string& ticker, t_mm2_ec& ec) const noexcept + t_orderbook_answer + mm2::get_orderbook(const std::string& base, const std::string& rel, t_mm2_ec& ec) const noexcept { + const std::string pair = base + "/" + rel; if (m_current_orderbook.empty()) { ec = dextop_error::orderbook_empty; return {}; } - if (m_current_orderbook.find(ticker) == m_current_orderbook.cend()) + if (m_current_orderbook.find(pair) == m_current_orderbook.cend()) { ec = dextop_error::orderbook_ticker_not_found; return {}; } - return m_current_orderbook.at(ticker); + return m_current_orderbook.at(pair); } void - mm2::process_orderbook(std::string base) + mm2::process_orderbook() { - auto&& coins = get_enabled_coins(); - std::vector out; - out.reserve(coins.size() - 1); - - for (auto&& current_coin: coins) + auto&& [base, rel] = m_synchronized_ticker_pair.get(); + t_orderbook_request request{.base = base, .rel = rel}; + auto answer = rpc_orderbook(std::move(request)); + if (answer.rpc_result_code not_eq -1) { - if (current_coin.ticker != base) - { - t_orderbook_request request{.base = base, .rel = current_coin.ticker}; - auto answer = rpc_orderbook(std::move(request)); - if (answer.rpc_result_code not_eq -1) - { - out.emplace_back(answer); - } - } + m_current_orderbook.insert_or_assign(base + "/" + rel, answer); } - m_current_orderbook.insert_or_assign(base, out); } void mm2::fetch_current_orderbook_thread() { - ////loguru::set_thread_name("orderbook thread"); spdlog::info("Fetch current orderbook"); //! If thread is not active ex: we are not on the trading page anymore, we continue sleeping. @@ -538,12 +528,7 @@ namespace atomic_dex return; } - // std::string current = (*m_current_orderbook.begin()).first; - - this->m_orderbook_mutex.try_lock(); - std::string copy = m_current_orderbook_ticker_base; - this->m_orderbook_mutex.unlock(); - process_orderbook(m_current_orderbook_ticker_base); + process_orderbook(); } void @@ -770,7 +755,8 @@ namespace atomic_dex t_coins coins = get_enabled_coins(); std::vector> futures; - if (not m_current_orderbook_ticker_rel.empty()) + auto&& [orderbook_ticker_base, orderbook_ticker_rel] = m_synchronized_ticker_pair.get(); + if (not m_synchronized_ticker_pair.get().second.empty()) { futures.reserve(2); } @@ -779,21 +765,21 @@ namespace atomic_dex futures.reserve(1); } - auto rpc_fees = [this]() { - t_get_trade_fee_request req{.coin = this->m_current_orderbook_ticker_base}; + auto rpc_fees = [this, orderbook_ticker_base = orderbook_ticker_base, orderbook_ticker_rel = orderbook_ticker_rel]() { + t_get_trade_fee_request req{.coin = orderbook_ticker_base}; auto answer = ::mm2::api::rpc_get_trade_fee(std::move(req)); if (answer.rpc_result_code == 200) { - this->m_trade_fees_registry.insert_or_assign(this->m_current_orderbook_ticker_base, answer); + this->m_trade_fees_registry.insert_or_assign(orderbook_ticker_base, answer); } - if (not m_current_orderbook_ticker_rel.empty()) + if (not orderbook_ticker_rel.empty()) { - t_get_trade_fee_request req_rel{.coin = this->m_current_orderbook_ticker_rel}; + t_get_trade_fee_request req_rel{.coin = orderbook_ticker_rel}; auto answer_rel = ::mm2::api::rpc_get_trade_fee(std::move(req_rel)); if (answer_rel.rpc_result_code == 200) { - this->m_trade_fees_registry.insert_or_assign(this->m_current_orderbook_ticker_rel, answer_rel); + this->m_trade_fees_registry.insert_or_assign(orderbook_ticker_rel, answer_rel); } } }; @@ -878,14 +864,7 @@ namespace atomic_dex spdlog::info("refreshing orderbook pair: [{} / {}]", evt.base, evt.rel); const auto key = evt.base; - { - std::scoped_lock lock(m_orderbook_mutex); - this->m_current_orderbook_ticker_base = evt.base; - if (not evt.rel.empty()) - { - this->m_current_orderbook_ticker_rel = evt.rel; - } - } + this->m_synchronized_ticker_pair = std::make_pair(evt.base, evt.rel); if (this->m_mm2_running) { diff --git a/src/atomic.dex.mm2.hpp b/src/atomic.dex.mm2.hpp index a3ddc49505..6c48b68c1c 100644 --- a/src/atomic.dex.mm2.hpp +++ b/src/atomic.dex.mm2.hpp @@ -72,23 +72,23 @@ namespace atomic_dex { private: //! Private typedefs - using t_mm2_time_point = std::chrono::high_resolution_clock::time_point; - using t_balance_registry = t_concurrent_reg; - using t_my_orders = t_concurrent_reg; - using t_tx_history_registry = t_concurrent_reg; - using t_tx_state_registry = t_concurrent_reg; - using t_orderbook_registry = t_concurrent_reg>; - using t_swaps_registry = t_concurrent_reg; - using t_swaps_avrg_datas = t_concurrent_reg; - using t_fees_registry = t_concurrent_reg; + using t_mm2_time_point = std::chrono::high_resolution_clock::time_point; + using t_balance_registry = t_concurrent_reg; + using t_my_orders = t_concurrent_reg; + using t_tx_history_registry = t_concurrent_reg; + using t_tx_state_registry = t_concurrent_reg; + using t_orderbook_registry = t_concurrent_reg; + using t_swaps_registry = t_concurrent_reg; + using t_swaps_avrg_datas = t_concurrent_reg; + using t_fees_registry = t_concurrent_reg; + using t_synchronized_ticker_pair = boost::synchronized_value>; //! Process reproc::process m_mm2_instance; //! Current orderbook - std::string m_current_orderbook_ticker_base{"KMD"}; - std::string m_current_orderbook_ticker_rel{"BTC"}; - std::mutex m_orderbook_mutex; + t_synchronized_ticker_pair m_synchronized_ticker_pair{std::make_pair("KMD", "BTC")}; + //! Timers t_mm2_time_point m_orderbook_clock; t_mm2_time_point m_info_clock; @@ -125,7 +125,7 @@ namespace atomic_dex void process_fees(); //! Refresh the orderbook registry (internal) - void process_orderbook(std::string base); + void process_orderbook(); public: //! Constructor @@ -229,7 +229,8 @@ namespace atomic_dex [[nodiscard]] t_coins get_enableable_coins() const noexcept; //! Get all coins - [[nodiscard]] t_coins get_all_coins() const noexcept;; + [[nodiscard]] t_coins get_all_coins() const noexcept; + ; //! Get Specific info about one coin [[nodiscard]] coin_config get_coin_info(const std::string& ticker) const; @@ -243,7 +244,7 @@ namespace atomic_dex ; //! Get Current orderbook - [[nodiscard]] std::vector get_orderbook(const std::string& ticker, t_mm2_ec& ec) const noexcept; + [[nodiscard]] t_orderbook_answer get_orderbook(const std::string& base, const std::string& rel, t_mm2_ec& ec) const noexcept; //! Get orders [[nodiscard]] ::mm2::api::my_orders_answer get_orders(const std::string& ticker, t_mm2_ec& ec) const noexcept; diff --git a/src/atomic.dex.qt.bindings.cpp b/src/atomic.dex.qt.bindings.cpp index f208a597ae..5d49f97ba7 100644 --- a/src/atomic.dex.qt.bindings.cpp +++ b/src/atomic.dex.qt.bindings.cpp @@ -19,6 +19,4 @@ namespace atomic_dex { qt_send_answer::qt_send_answer(QObject* parent) : QObject(parent) {} - qt_orderbook::qt_orderbook(QObject* parent) : QObject(parent) {} - qt_ordercontent::qt_ordercontent(QObject* parent) : QObject(parent) {} } // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.bindings.hpp b/src/atomic.dex.qt.bindings.hpp index 50a3c70cfb..55193cc68d 100644 --- a/src/atomic.dex.qt.bindings.hpp +++ b/src/atomic.dex.qt.bindings.hpp @@ -30,68 +30,6 @@ namespace atomic_dex { - struct qt_ordercontent : QObject - { - Q_OBJECT - public: - explicit qt_ordercontent(QObject* parent = nullptr); - QString m_price; - QString m_maxvolume; - - Q_PROPERTY(QString price READ get_price CONSTANT MEMBER m_price) - Q_PROPERTY(QString maxvolume READ get_maxvolume CONSTANT MEMBER m_maxvolume) - - [[nodiscard]] QString get_price() const noexcept - { - return m_price; - } - - [[nodiscard]] QString - get_maxvolume() const noexcept - { - return m_maxvolume; - } - }; - - struct qt_orderbook : QObject - { - Q_OBJECT - public: - explicit qt_orderbook(QObject* parent = nullptr); - QObjectList m_bids; - QObjectList m_asks; - QString m_base; - QString m_rel; - - Q_PROPERTY(QString rel READ get_rel CONSTANT MEMBER m_rel) - Q_PROPERTY(QString base READ get_base CONSTANT MEMBER m_base) - Q_PROPERTY(QList bids READ get_bids CONSTANT MEMBER m_bids) - Q_PROPERTY(QList asks READ get_asks CONSTANT MEMBER m_asks) - - [[nodiscard]] QObjectList get_bids() const noexcept - { - return m_bids; - } - - [[nodiscard]] QObjectList - get_asks() const noexcept - { - return m_asks; - } - - [[nodiscard]] QString - get_rel() const noexcept - { - return m_rel; - } - - [[nodiscard]] QString - get_base() const noexcept - { - return m_base; - } - }; - struct qt_send_answer : QObject { Q_OBJECT @@ -246,30 +184,4 @@ namespace atomic_dex } return obj; } - - inline QObject* - to_qt_binding(t_orderbook_answer&& answer, QObject* parent) - { - auto* obj = new qt_orderbook(parent); - obj->m_rel = QString::fromStdString(answer.rel); - obj->m_base = QString::fromStdString(answer.base); - obj->m_bids.reserve(answer.bids.size()); - obj->m_asks.reserve(answer.asks.size()); - for (auto&& bid: answer.bids) - { - auto* q_bid = new qt_ordercontent(parent); - q_bid->m_maxvolume = QString::fromStdString(bid.maxvolume); - q_bid->m_price = QString::fromStdString(bid.price); - obj->m_bids.append(q_bid); - } - - for (auto&& ask: answer.asks) - { - auto* q_ask = new qt_ordercontent(parent); - q_ask->m_maxvolume = QString::fromStdString(ask.maxvolume); - q_ask->m_price = QString::fromStdString(ask.price); - obj->m_asks.append(q_ask); - } - return obj; - } } // namespace atomic_dex \ No newline at end of file From 4ce82686a08a22f7d36dec0a4f9d0c260dec2870 Mon Sep 17 00:00:00 2001 From: milerius Date: Tue, 28 Jul 2020 14:32:02 +0200 Subject: [PATCH 009/515] feat(orderbook): continue revamp of old orderbook and prepare transition --- src/atomic.dex.mm2.cpp | 3 ++- src/atomic.dex.mm2.hpp | 2 +- src/atomic.dex.qt.orderbook.model.cpp | 35 ++++++++++++++++++++++++++- src/atomic.dex.qt.orderbook.model.hpp | 22 ++++++++++++++++- 4 files changed, 58 insertions(+), 4 deletions(-) diff --git a/src/atomic.dex.mm2.cpp b/src/atomic.dex.mm2.cpp index 02feac00ee..e22c1bc02a 100644 --- a/src/atomic.dex.mm2.cpp +++ b/src/atomic.dex.mm2.cpp @@ -488,8 +488,9 @@ namespace atomic_dex } t_orderbook_answer - mm2::get_orderbook(const std::string& base, const std::string& rel, t_mm2_ec& ec) const noexcept + mm2::get_orderbook(t_mm2_ec& ec) const noexcept { + auto&& [base, rel] = this->m_synchronized_ticker_pair.get(); const std::string pair = base + "/" + rel; if (m_current_orderbook.empty()) { diff --git a/src/atomic.dex.mm2.hpp b/src/atomic.dex.mm2.hpp index 6c48b68c1c..6c6dff5674 100644 --- a/src/atomic.dex.mm2.hpp +++ b/src/atomic.dex.mm2.hpp @@ -244,7 +244,7 @@ namespace atomic_dex ; //! Get Current orderbook - [[nodiscard]] t_orderbook_answer get_orderbook(const std::string& base, const std::string& rel, t_mm2_ec& ec) const noexcept; + [[nodiscard]] t_orderbook_answer get_orderbook(t_mm2_ec& ec) const noexcept; //! Get orders [[nodiscard]] ::mm2::api::my_orders_answer get_orders(const std::string& ticker, t_mm2_ec& ec) const noexcept; diff --git a/src/atomic.dex.qt.orderbook.model.cpp b/src/atomic.dex.qt.orderbook.model.cpp index f2e3f8349d..a1ae388eb6 100644 --- a/src/atomic.dex.qt.orderbook.model.cpp +++ b/src/atomic.dex.qt.orderbook.model.cpp @@ -14,9 +14,42 @@ * * ******************************************************************************/ +//! PCH +#include "atomic.dex.pch.hpp" + +//! Project #include "atomic.dex.qt.orderbook.model.hpp" namespace atomic_dex { + orderbook_model::orderbook_model(kind orderbook_kind, QObject* parent) : QAbstractTableModel(parent), m_current_orderbook_kind(orderbook_kind) + { + spdlog::trace("{} l{} f[{}]", __FUNCTION__, __LINE__, fs::path(__FILE__).filename().string()); + spdlog::trace("orderbook model created"); + } + + orderbook_model::~orderbook_model() noexcept + { + spdlog::trace("{} l{} f[{}]", __FUNCTION__, __LINE__, fs::path(__FILE__).filename().string()); + spdlog::trace("orderbook model destroyed"); + } + + int + orderbook_model::rowCount([[maybe_unused]] const QModelIndex& parent) const + { + return 0; + } + + int + orderbook_model::columnCount([[maybe_unused]] const QModelIndex& parent) const + { + return 0; + } + + QVariant + orderbook_model::data([[maybe_unused]] const QModelIndex& index, [[maybe_unused]] int role) const + { + return QVariant(); + } -} \ No newline at end of file +} // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.orderbook.model.hpp b/src/atomic.dex.qt.orderbook.model.hpp index 083459185d..a01a3b7a41 100644 --- a/src/atomic.dex.qt.orderbook.model.hpp +++ b/src/atomic.dex.qt.orderbook.model.hpp @@ -16,7 +16,27 @@ #pragma once +#include + namespace atomic_dex { + class orderbook_model final : public QAbstractTableModel + { + public: + enum class kind + { + asks, + bids + }; + + orderbook_model(kind orderbook_kind, QObject* parent = nullptr); + ~orderbook_model() noexcept final; + + [[nodiscard]] int rowCount(const QModelIndex& parent) const final; + [[nodiscard]] int columnCount(const QModelIndex& parent) const final; + [[nodiscard]] QVariant data(const QModelIndex& index, int role) const final; -} \ No newline at end of file + private: + kind m_current_orderbook_kind{kind::asks}; + }; +} // namespace atomic_dex \ No newline at end of file From 63fc457426c0bb99024919d2aec5492e2233c134 Mon Sep 17 00:00:00 2001 From: milerius Date: Tue, 28 Jul 2020 14:45:22 +0200 Subject: [PATCH 010/515] feat(orderbook): using list model --- src/atomic.dex.qt.orderbook.model.cpp | 8 +------- src/atomic.dex.qt.orderbook.model.hpp | 5 ++--- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/atomic.dex.qt.orderbook.model.cpp b/src/atomic.dex.qt.orderbook.model.cpp index a1ae388eb6..3b5be9cdf2 100644 --- a/src/atomic.dex.qt.orderbook.model.cpp +++ b/src/atomic.dex.qt.orderbook.model.cpp @@ -22,7 +22,7 @@ namespace atomic_dex { - orderbook_model::orderbook_model(kind orderbook_kind, QObject* parent) : QAbstractTableModel(parent), m_current_orderbook_kind(orderbook_kind) + orderbook_model::orderbook_model(kind orderbook_kind, QObject* parent) : QAbstractListModel(parent), m_current_orderbook_kind(orderbook_kind) { spdlog::trace("{} l{} f[{}]", __FUNCTION__, __LINE__, fs::path(__FILE__).filename().string()); spdlog::trace("orderbook model created"); @@ -40,12 +40,6 @@ namespace atomic_dex return 0; } - int - orderbook_model::columnCount([[maybe_unused]] const QModelIndex& parent) const - { - return 0; - } - QVariant orderbook_model::data([[maybe_unused]] const QModelIndex& index, [[maybe_unused]] int role) const { diff --git a/src/atomic.dex.qt.orderbook.model.hpp b/src/atomic.dex.qt.orderbook.model.hpp index a01a3b7a41..2b6dd155bd 100644 --- a/src/atomic.dex.qt.orderbook.model.hpp +++ b/src/atomic.dex.qt.orderbook.model.hpp @@ -16,11 +16,11 @@ #pragma once -#include +#include namespace atomic_dex { - class orderbook_model final : public QAbstractTableModel + class orderbook_model final : public QAbstractListModel { public: enum class kind @@ -33,7 +33,6 @@ namespace atomic_dex ~orderbook_model() noexcept final; [[nodiscard]] int rowCount(const QModelIndex& parent) const final; - [[nodiscard]] int columnCount(const QModelIndex& parent) const final; [[nodiscard]] QVariant data(const QModelIndex& index, int role) const final; private: From 9cf920d08078a731c1980573794cbadcd81c1a91 Mon Sep 17 00:00:00 2001 From: milerius Date: Tue, 28 Jul 2020 15:34:00 +0200 Subject: [PATCH 011/515] feat(orderbook): continue live orderbook --- src/atomic.dex.mm2.api.cpp | 29 +++++++++++++++------------ src/atomic.dex.mm2.api.hpp | 1 + src/atomic.dex.qt.orderbook.model.cpp | 27 ++++++++++++++++++++++--- src/atomic.dex.qt.orderbook.model.hpp | 15 ++++++++++++-- 4 files changed, 54 insertions(+), 18 deletions(-) diff --git a/src/atomic.dex.mm2.api.cpp b/src/atomic.dex.mm2.api.cpp index 7c096b130d..880a55ebef 100644 --- a/src/atomic.dex.mm2.api.cpp +++ b/src/atomic.dex.mm2.api.cpp @@ -222,9 +222,9 @@ namespace mm2::api using namespace date; using namespace std::chrono; date::sys_seconds tp{seconds{cfg.timestamp}}; - auto tp_zoned = date::make_zoned(current_zone(), tp); - std::string s = date::format("%e %b %Y, %I:%M", tp_zoned); - cfg.timestamp_as_date = std::move(s); + auto tp_zoned = date::make_zoned(current_zone(), tp); + std::string s = date::format("%e %b %Y, %I:%M", tp_zoned); + cfg.timestamp_as_date = std::move(s); } void @@ -415,6 +415,8 @@ namespace mm2::api contents.price = contents.price; } contents.maxvolume = adjust_precision(contents.maxvolume); + t_float_50 total_f = t_float_50(contents.price) * t_float_50(contents.maxvolume); + contents.total = adjust_precision(total_f.str()); } void @@ -434,8 +436,8 @@ namespace mm2::api j.at("timestamp").get_to(answer.timestamp); sys_time tp{std::chrono::milliseconds{answer.timestamp}}; - auto tp_zoned = date::make_zoned(current_zone(), tp); - answer.human_timestamp = date::format("%Y-%m-%d %I:%M:%S", tp_zoned); + auto tp_zoned = date::make_zoned(current_zone(), tp); + answer.human_timestamp = date::format("%Y-%m-%d %I:%M:%S", tp_zoned); } void @@ -669,12 +671,12 @@ namespace mm2::api j.at("type").get_to(contents.type); j.at("recoverable").get_to(contents.funds_recoverable); - contents.taker_amount = adjust_precision(contents.taker_amount); - contents.maker_amount = adjust_precision(contents.maker_amount); - contents.events = nlohmann::json::array(); + contents.taker_amount = adjust_precision(contents.taker_amount); + contents.maker_amount = adjust_precision(contents.maker_amount); + contents.events = nlohmann::json::array(); if (j.contains("my_info")) { - contents.my_info = j.at("my_info"); + contents.my_info = j.at("my_info"); if (not contents.my_info.is_null()) { contents.my_info["other_amount"] = adjust_precision(contents.my_info["other_amount"].get()); @@ -691,7 +693,7 @@ namespace mm2::api const nlohmann::json& j_evt = content.at("event"); auto timestamp = content.at("timestamp").get(); auto tp = sys_milliseconds{std::chrono::milliseconds{timestamp}}; - auto tp_zoned = date::make_zoned(current_zone(), tp); + auto tp_zoned = date::make_zoned(current_zone(), tp); std::string human_date = date::format("%F %T", tp_zoned); auto evt_type = j_evt.at("type").get(); @@ -699,8 +701,8 @@ namespace mm2::api &total_time_in_seconds](nlohmann::json& jf_evt, const std::string& event_type, const std::string& previous_event) { if (event_timestamp_registry.count(previous_event) != 0) { - std::int64_t ts = event_timestamp_registry.at(previous_event); - jf_evt["started_at"] = ts; + std::int64_t ts = event_timestamp_registry.at(previous_event); + jf_evt["started_at"] = ts; std::int64_t ts2 = jf_evt.at("timestamp").get(); std::stringstream ss; sys_time t1{std::chrono::milliseconds{ts}}; @@ -875,7 +877,8 @@ namespace mm2::api } catch (const std::exception& error) { - spdlog::error("{} l{} f[{}], exception caught {} for rpc {}", __FUNCTION__, __LINE__, fs::path(__FILE__).filename().string(), error.what(), rpc_command); + spdlog::error( + "{} l{} f[{}], exception caught {} for rpc {}", __FUNCTION__, __LINE__, fs::path(__FILE__).filename().string(), error.what(), rpc_command); answer.rpc_result_code = -1; answer.raw_result = error.what(); } diff --git a/src/atomic.dex.mm2.api.hpp b/src/atomic.dex.mm2.api.hpp index 4fd618ca50..eb30091845 100644 --- a/src/atomic.dex.mm2.api.hpp +++ b/src/atomic.dex.mm2.api.hpp @@ -388,6 +388,7 @@ namespace mm2::api std::string pubkey; std::size_t age; std::size_t zcredits; + std::string total; }; void from_json(const nlohmann::json& j, order_contents& contents); diff --git a/src/atomic.dex.qt.orderbook.model.cpp b/src/atomic.dex.qt.orderbook.model.cpp index 3b5be9cdf2..4651514fd5 100644 --- a/src/atomic.dex.qt.orderbook.model.cpp +++ b/src/atomic.dex.qt.orderbook.model.cpp @@ -37,13 +37,34 @@ namespace atomic_dex int orderbook_model::rowCount([[maybe_unused]] const QModelIndex& parent) const { - return 0; + return m_current_orderbook_kind == kind::asks ? m_model_data->asks.size() : m_model_data->bids.size(); } QVariant - orderbook_model::data([[maybe_unused]] const QModelIndex& index, [[maybe_unused]] int role) const + orderbook_model::data(const QModelIndex& index, int role) const { - return QVariant(); + if (!hasIndex(index.row(), index.column(), index.parent()) || this->rowCount() == 0) + { + return {}; + } + switch (static_cast(role)) + { + case PriceRole: + return m_current_orderbook_kind == kind::asks ? QString::fromStdString(m_model_data->asks.at(index.row()).price) + : QString::fromStdString(m_model_data->bids.at(index.row()).price); + case QuantityRole: + return m_current_orderbook_kind == kind::asks ? QString::fromStdString(m_model_data->asks.at(index.row()).maxvolume) + : QString::fromStdString(m_model_data->bids.at(index.row()).maxvolume); + case TotalRole: + return m_current_orderbook_kind == kind::asks ? QString::fromStdString(m_model_data->asks.at(index.row()).total) + : QString::fromStdString(m_model_data->bids.at(index.row()).total); + } + } + + QHash + orderbook_model::roleNames() const + { + return {{PriceRole, "price"}, {QuantityRole, "quantity"}, {TotalRole, "total"}}; } } // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.orderbook.model.hpp b/src/atomic.dex.qt.orderbook.model.hpp index 2b6dd155bd..8cfaba9599 100644 --- a/src/atomic.dex.qt.orderbook.model.hpp +++ b/src/atomic.dex.qt.orderbook.model.hpp @@ -18,6 +18,8 @@ #include +#include "atomic.dex.mm2.api.hpp" + namespace atomic_dex { class orderbook_model final : public QAbstractListModel @@ -29,13 +31,22 @@ namespace atomic_dex bids }; + enum OrderbookRoles + { + PriceRole, + QuantityRole, + TotalRole + }; + orderbook_model(kind orderbook_kind, QObject* parent = nullptr); ~orderbook_model() noexcept final; - [[nodiscard]] int rowCount(const QModelIndex& parent) const final; + [[nodiscard]] int rowCount(const QModelIndex& parent = QModelIndex()) const final; [[nodiscard]] QVariant data(const QModelIndex& index, int role) const final; + [[nodiscard]] QHash roleNames() const final; private: - kind m_current_orderbook_kind{kind::asks}; + kind m_current_orderbook_kind{kind::asks}; + t_orderbook_answer* m_model_data; }; } // namespace atomic_dex \ No newline at end of file From e6ec778de6bc84acc002134658630bfd931c46b3 Mon Sep 17 00:00:00 2001 From: milerius Date: Tue, 28 Jul 2020 15:39:51 +0200 Subject: [PATCH 012/515] feat(orderbook): instantiate asks and bids --- src/atomic.dex.qt.orderbook.cpp | 16 +++++++++++++++- src/atomic.dex.qt.orderbook.hpp | 15 +++++++++++++++ src/atomic.dex.qt.orderbook.model.hpp | 4 ++-- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/atomic.dex.qt.orderbook.cpp b/src/atomic.dex.qt.orderbook.cpp index 1a1ee9d8c1..48df2a0405 100644 --- a/src/atomic.dex.qt.orderbook.cpp +++ b/src/atomic.dex.qt.orderbook.cpp @@ -18,7 +18,9 @@ namespace atomic_dex { - qt_orderbook_wrapper::qt_orderbook_wrapper(ag::ecs::system_manager& system_manager, QObject* parent) : QObject(parent), m_system_manager(system_manager) + qt_orderbook_wrapper::qt_orderbook_wrapper(ag::ecs::system_manager& system_manager, QObject* parent) : + QObject(parent), m_system_manager(system_manager), m_asks(new orderbook_model(orderbook_model::kind::asks, this)), + m_bids(new orderbook_model(orderbook_model::kind::bids, this)) { spdlog::trace("{} l{} f[{}]", __FUNCTION__, __LINE__, fs::path(__FILE__).filename().string()); spdlog::trace("orderbook wrapper object created"); @@ -29,4 +31,16 @@ namespace atomic_dex spdlog::trace("{} l{} f[{}]", __FUNCTION__, __LINE__, fs::path(__FILE__).filename().string()); spdlog::trace("orderbook wrapper object destroyed"); } + + atomic_dex::orderbook_model* + atomic_dex::qt_orderbook_wrapper::get_asks() const noexcept + { + return m_asks; + } + + orderbook_model* + qt_orderbook_wrapper::get_bids() const noexcept + { + return m_bids; + } } // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.orderbook.hpp b/src/atomic.dex.qt.orderbook.hpp index 2847601b64..5228a982bc 100644 --- a/src/atomic.dex.qt.orderbook.hpp +++ b/src/atomic.dex.qt.orderbook.hpp @@ -22,16 +22,31 @@ //! PCH #include "atomic.dex.pch.hpp" +//! Project +#include "atomic.dex.qt.orderbook.model.hpp" + namespace atomic_dex { class qt_orderbook_wrapper final : public QObject { Q_OBJECT + Q_PROPERTY(orderbook_model* asks READ get_asks NOTIFY asksChanged) + Q_PROPERTY(orderbook_model* bids READ get_bids NOTIFY bidsChanged) public: qt_orderbook_wrapper(ag::ecs::system_manager& system_manager, QObject* parent = nullptr); ~qt_orderbook_wrapper() noexcept final; + public: + [[nodiscard]] orderbook_model* get_asks() const noexcept; + [[nodiscard]] orderbook_model* get_bids() const noexcept; + + public: + void asksChanged(); + void bidsChanged(); + private: ag::ecs::system_manager& m_system_manager; + orderbook_model* m_asks; + orderbook_model* m_bids; }; } // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.orderbook.model.hpp b/src/atomic.dex.qt.orderbook.model.hpp index 8cfaba9599..ad1073069c 100644 --- a/src/atomic.dex.qt.orderbook.model.hpp +++ b/src/atomic.dex.qt.orderbook.model.hpp @@ -41,8 +41,8 @@ namespace atomic_dex orderbook_model(kind orderbook_kind, QObject* parent = nullptr); ~orderbook_model() noexcept final; - [[nodiscard]] int rowCount(const QModelIndex& parent = QModelIndex()) const final; - [[nodiscard]] QVariant data(const QModelIndex& index, int role) const final; + [[nodiscard]] int rowCount(const QModelIndex& parent = QModelIndex()) const final; + [[nodiscard]] QVariant data(const QModelIndex& index, int role) const final; [[nodiscard]] QHash roleNames() const final; private: From 523389c827c74f07339c1ea9b1642baa3d55d38c Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 28 Jul 2020 16:41:07 +0300 Subject: [PATCH 013/515] feat(gui): start making the new layout --- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 90 +++++++++---------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index 20c875dc1b..c86276c7dd 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -10,6 +10,7 @@ Item { id: exchange_trade property string action_result + readonly property int layout_margin: 20 // Override property var onOrderSuccess: () => {} @@ -179,7 +180,7 @@ Item { function updateOrderbook() { fillTickersIfEmpty() - orderbook_model = API.get().get_orderbook(getTicker(true)) + orderbook_model = API.mockAPI.get_orderbook(getTicker(true)) orderbook_timer.running = true updateTradeInfo() } @@ -383,60 +384,59 @@ Item { anchors.fill: parent + Item { + Layout.fillWidth: true + Layout.fillHeight: true + Layout.bottomMargin: layout_margin - InnerBackground { - id: graph_bg - - Layout.alignment: Qt.AlignTop + InnerBackground { + id: graph_bg - visible: chart.pair_supported + anchors.left: parent.left + anchors.right: forms.left + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.rightMargin: layout_margin - Layout.fillWidth: true - Layout.fillHeight: true - implicitHeight: wallet.height*0.6 + visible: chart.pair_supported - CandleStickChart { - id: chart - width: graph_bg.width - height: graph_bg.height + CandleStickChart { + id: chart + anchors.fill: parent + } } - } - RowLayout { - Layout.alignment: Qt.AlignVCenter - spacing: 0 + Item { + id: forms + width: 400 + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom - // Sell - OrderForm { - id: form_base - Layout.fillWidth: true - my_side: true - } + // Sell + OrderForm { + id: form_base + + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.verticalCenter + anchors.bottomMargin: layout_margin*0.5 - FloatingBackground { - id: trade_icon_bg - z: 1 - radius: 100 - width: 75 - height: width - auto_set_size: false - - content: DefaultImage { - source: General.image_path + "trade_icon.svg" - Layout.alignment: Qt.AlignVCenter - fillMode: Image.PreserveAspectFit - width: trade_icon_bg.width*0.4 - height: width + my_side: true } - } - // Receive - OrderForm { - id: form_rel - Layout.fillWidth: true - Layout.preferredHeight: form_base.height - column_layout.height: form_base.height - field.enabled: enabled && !orderIsSelected() + // Receive + OrderForm { + id: form_rel + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.verticalCenter + anchors.bottom: parent.bottom + anchors.topMargin: form_base.anchors.bottomMargin + + field.enabled: enabled && !orderIsSelected() + } } } From 844f4010282d6b7819c9ed9ca3949025d4ed2200 Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 28 Jul 2020 16:43:26 +0300 Subject: [PATCH 014/515] feat(gui): remove circle masks --- .../qml/Exchange/Trade/OrderForm.qml | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index 7ef564cfce..82d2e6bf4d 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -470,23 +470,4 @@ FloatingBackground { onClicked: confirm_trade_modal.open() } } - - - opacity_mask_enabled: true - mask: OpacityMask { - source: rect - invert: true - maskSource: Item { - width: rect.width; - height: rect.height; - Rectangle { - anchors.verticalCenter: parent.verticalCenter - anchors.left: my_side ? parent.right : undefined - anchors.leftMargin: my_side ? -17.5 : 0 - anchors.right: my_side ? undefined : parent.left - anchors.rightMargin: my_side ? 0 : -17.5 - width: 110; height: width; radius: Infinity - } - } - } } From 2de02d24a0f5df34d66feee3849c27dacdbae304 Mon Sep 17 00:00:00 2001 From: milerius Date: Tue, 28 Jul 2020 15:58:56 +0200 Subject: [PATCH 015/515] feat(orderbook): finalize first logic of live orderbook --- src/atomic.dex.app.cpp | 21 ++++++++++++++ src/atomic.dex.app.hpp | 42 ++++++++++++++------------- src/atomic.dex.events.hpp | 1 + src/atomic.dex.mm2.cpp | 21 +++++++------- src/atomic.dex.qt.orderbook.cpp | 12 ++++++-- src/atomic.dex.qt.orderbook.hpp | 2 ++ src/atomic.dex.qt.orderbook.model.cpp | 25 +++++++++++----- src/atomic.dex.qt.orderbook.model.hpp | 5 ++-- 8 files changed, 87 insertions(+), 42 deletions(-) diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index 6a9949f829..9d85109959 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -290,6 +290,16 @@ namespace atomic_dex this->m_orders->refresh_or_insert_swaps(); } break; + case action::post_process_orderbook_finished: + if (mm2.is_mm2_running()) + { + std::error_code ec; + t_orderbook_answer result = this->get_mm2().get_orderbook(ec); + if (!ec) + { + this->m_orderbook->refresh_orderbook(result); + } + } case action::refresh_update_status: spdlog::trace("refreshing update status in GUI"); const auto& update_service_sys = this->system_manager_.get_system(); @@ -845,6 +855,7 @@ namespace atomic_dex get_dispatcher().sink().disconnect<&application::on_refresh_ohlc_event>(*this); get_dispatcher().sink().disconnect<&application::on_process_orders_finished_event>(*this); get_dispatcher().sink().disconnect<&application::on_process_swaps_finished_event>(*this); + get_dispatcher().sink().disconnect<&application::on_process_orderbook_finished_event>(*this); get_dispatcher().sink().disconnect<&application::on_start_fetching_new_ohlc_data_event>(*this); this->m_need_a_full_refresh_of_mm2 = true; @@ -868,6 +879,7 @@ namespace atomic_dex get_dispatcher().sink().connect<&application::on_refresh_ohlc_event>(*this); get_dispatcher().sink().connect<&application::on_process_orders_finished_event>(*this); get_dispatcher().sink().connect<&application::on_process_swaps_finished_event>(*this); + get_dispatcher().sink().connect<&application::on_process_orderbook_finished_event>(*this); get_dispatcher().sink().connect<&application::on_start_fetching_new_ohlc_data_event>(*this); } @@ -1451,4 +1463,13 @@ namespace atomic_dex { return m_orderbook; } + + void + application::on_process_orderbook_finished_event(const process_orderbook_finished&) noexcept + { + if (not m_about_to_exit_app) + { + this->m_actions_queue.push(action::post_process_orderbook_finished); + } + } } // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.app.hpp b/src/atomic.dex.app.hpp index b542d208c7..bb98fb2711 100644 --- a/src/atomic.dex.app.hpp +++ b/src/atomic.dex.app.hpp @@ -36,10 +36,10 @@ #include "atomic.dex.qt.bindings.hpp" #include "atomic.dex.qt.candlestick.charts.model.hpp" #include "atomic.dex.qt.current.coin.infos.hpp" +#include "atomic.dex.qt.orderbook.hpp" #include "atomic.dex.qt.orders.model.hpp" #include "atomic.dex.qt.portfolio.model.hpp" #include "atomic.dex.qt.wallet.manager.hpp" -#include "atomic.dex.qt.orderbook.hpp" namespace ag = antara::gaming; @@ -89,7 +89,8 @@ namespace atomic_dex refresh_portfolio_ticker_balance = 4, refresh_update_status = 5, post_process_orders_finished = 6, - post_process_swaps_finished = 7 + post_process_swaps_finished = 7, + post_process_orderbook_finished = 8 }; public: @@ -111,20 +112,21 @@ namespace atomic_dex void on_refresh_update_status_event(const refresh_update_status&) noexcept; void on_process_orders_finished_event(const process_orders_finished&) noexcept; void on_process_swaps_finished_event(const process_swaps_finished&) noexcept; + void on_process_orderbook_finished_event(const process_orderbook_finished&) noexcept; void on_start_fetching_new_ohlc_data_event(const start_fetching_new_ohlc_data&); //! Properties Getter - static const QString& get_empty_string(); - mm2& get_mm2() noexcept; - const mm2& get_mm2() const noexcept; - coinpaprika_provider& get_paprika() noexcept; - entt::dispatcher& get_dispatcher() noexcept; - QObject* get_current_coin_info() const noexcept; - addressbook_model* get_addressbook() const noexcept; - portfolio_model* get_portfolio() const noexcept; - orders_model* get_orders() const noexcept; - candlestick_charts_model* get_candlestick_charts() const noexcept; - qt_orderbook_wrapper* get_orderbook_wrapper() const noexcept; + static const QString& get_empty_string(); + mm2& get_mm2() noexcept; + const mm2& get_mm2() const noexcept; + coinpaprika_provider& get_paprika() noexcept; + entt::dispatcher& get_dispatcher() noexcept; + QObject* get_current_coin_info() const noexcept; + addressbook_model* get_addressbook() const noexcept; + portfolio_model* get_portfolio() const noexcept; + orders_model* get_orders() const noexcept; + candlestick_charts_model* get_candlestick_charts() const noexcept; + qt_orderbook_wrapper* get_orderbook_wrapper() const noexcept; QVariantList get_enabled_coins() const noexcept; QVariantList get_enableable_coins() const noexcept; QString get_current_currency() const noexcept; @@ -203,15 +205,15 @@ namespace atomic_dex Q_INVOKABLE QString place_sell_order( const QString& base, const QString& rel, const QString& price, const QString& volume, bool is_created_order, const QString& price_denom, const QString& price_numer); - Q_INVOKABLE void set_current_orderbook(const QString& base, const QString& rel); - Q_INVOKABLE bool do_i_have_enough_funds(const QString& ticker, const QString& amount) const; - Q_INVOKABLE bool disable_coins(const QStringList& coins); - Q_INVOKABLE bool is_claiming_ready(const QString& ticker); + Q_INVOKABLE void set_current_orderbook(const QString& base, const QString& rel); + Q_INVOKABLE bool do_i_have_enough_funds(const QString& ticker, const QString& amount) const; + Q_INVOKABLE bool disable_coins(const QStringList& coins); + Q_INVOKABLE bool is_claiming_ready(const QString& ticker); Q_INVOKABLE QObject* claim_rewards(const QString& ticker); - Q_INVOKABLE QString get_cex_rates(const QString& base, const QString& rel); - Q_INVOKABLE QString get_fiat_from_amount(const QString& ticker, const QString& amount); + Q_INVOKABLE QString get_cex_rates(const QString& base, const QString& rel); + Q_INVOKABLE QString get_fiat_from_amount(const QString& ticker, const QString& amount); Q_INVOKABLE QVariantMap find_closest_ohlc_data(int range, int timestamp); Q_INVOKABLE QVariant get_coin_info(const QString& ticker); Q_INVOKABLE bool export_swaps(const QString& csv_filename) noexcept; @@ -289,7 +291,7 @@ namespace atomic_dex std::atomic_bool m_candlestick_need_a_reset{false}; //! Orderbook Model Wrapper - qt_orderbook_wrapper* m_orderbook; + qt_orderbook_wrapper* m_orderbook; std::atomic_bool m_about_to_exit_app{false}; }; diff --git a/src/atomic.dex.events.hpp b/src/atomic.dex.events.hpp index 0c97854b69..d4ec1cae35 100644 --- a/src/atomic.dex.events.hpp +++ b/src/atomic.dex.events.hpp @@ -32,6 +32,7 @@ namespace atomic_dex using refresh_update_status = entt::tag<"gui_refresh_update_status"_hs>; using process_orders_finished = entt::tag<"gui_process_orders_finished"_hs>; using process_swaps_finished = entt::tag<"gui_process_swaps_finished"_hs>; + using process_orderbook_finished = entt::tag<"gui_process_orderbook_finished"_hs>; struct refresh_ohlc_needed { diff --git a/src/atomic.dex.mm2.cpp b/src/atomic.dex.mm2.cpp index e22c1bc02a..4f8de7cbfe 100644 --- a/src/atomic.dex.mm2.cpp +++ b/src/atomic.dex.mm2.cpp @@ -490,7 +490,7 @@ namespace atomic_dex t_orderbook_answer mm2::get_orderbook(t_mm2_ec& ec) const noexcept { - auto&& [base, rel] = this->m_synchronized_ticker_pair.get(); + auto&& [base, rel] = this->m_synchronized_ticker_pair.get(); const std::string pair = base + "/" + rel; if (m_current_orderbook.empty()) { @@ -514,6 +514,7 @@ namespace atomic_dex if (answer.rpc_result_code not_eq -1) { m_current_orderbook.insert_or_assign(base + "/" + rel, answer); + this->dispatcher_.trigger(); } } @@ -828,15 +829,15 @@ namespace atomic_dex { tx_infos current_info{ - .am_i_sender = current.my_balance_change[0] == '-', - .confirmations = current.confirmations.has_value() ? current.confirmations.value() : 0, - .from = current.from, - .to = current.to, - .date = current.timestamp_as_date, - .timestamp = current.timestamp, - .tx_hash = current.tx_hash, - .fees = current.fee_details.normal_fees.has_value() ? current.fee_details.normal_fees.value().amount - : current.fee_details.erc_fees.value().total_fee, + .am_i_sender = current.my_balance_change[0] == '-', + .confirmations = current.confirmations.has_value() ? current.confirmations.value() : 0, + .from = current.from, + .to = current.to, + .date = current.timestamp_as_date, + .timestamp = current.timestamp, + .tx_hash = current.tx_hash, + .fees = current.fee_details.normal_fees.has_value() ? current.fee_details.normal_fees.value().amount + : current.fee_details.erc_fees.value().total_fee, .my_balance_change = current.my_balance_change, .total_amount = current.total_amount, .block_height = current.block_height, diff --git a/src/atomic.dex.qt.orderbook.cpp b/src/atomic.dex.qt.orderbook.cpp index 48df2a0405..a8f76fcbd0 100644 --- a/src/atomic.dex.qt.orderbook.cpp +++ b/src/atomic.dex.qt.orderbook.cpp @@ -19,8 +19,8 @@ namespace atomic_dex { qt_orderbook_wrapper::qt_orderbook_wrapper(ag::ecs::system_manager& system_manager, QObject* parent) : - QObject(parent), m_system_manager(system_manager), m_asks(new orderbook_model(orderbook_model::kind::asks, this)), - m_bids(new orderbook_model(orderbook_model::kind::bids, this)) + QObject(parent), m_system_manager(system_manager), m_asks(new orderbook_model(m_last_orderbook, orderbook_model::kind::asks, this)), + m_bids(new orderbook_model(m_last_orderbook, orderbook_model::kind::bids, this)) { spdlog::trace("{} l{} f[{}]", __FUNCTION__, __LINE__, fs::path(__FILE__).filename().string()); spdlog::trace("orderbook wrapper object created"); @@ -43,4 +43,12 @@ namespace atomic_dex { return m_bids; } + + void + qt_orderbook_wrapper::refresh_orderbook(t_orderbook_answer answer) + { + this->m_last_orderbook = std::move(answer); + this->m_asks->reset_orderbook(m_last_orderbook); + this->m_bids->reset_orderbook(m_last_orderbook); + } } // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.orderbook.hpp b/src/atomic.dex.qt.orderbook.hpp index 5228a982bc..05599b6c7c 100644 --- a/src/atomic.dex.qt.orderbook.hpp +++ b/src/atomic.dex.qt.orderbook.hpp @@ -37,6 +37,7 @@ namespace atomic_dex ~qt_orderbook_wrapper() noexcept final; public: + void refresh_orderbook(t_orderbook_answer answer); [[nodiscard]] orderbook_model* get_asks() const noexcept; [[nodiscard]] orderbook_model* get_bids() const noexcept; @@ -46,6 +47,7 @@ namespace atomic_dex private: ag::ecs::system_manager& m_system_manager; + t_orderbook_answer m_last_orderbook; orderbook_model* m_asks; orderbook_model* m_bids; }; diff --git a/src/atomic.dex.qt.orderbook.model.cpp b/src/atomic.dex.qt.orderbook.model.cpp index 4651514fd5..5ae1fe42d8 100644 --- a/src/atomic.dex.qt.orderbook.model.cpp +++ b/src/atomic.dex.qt.orderbook.model.cpp @@ -22,7 +22,8 @@ namespace atomic_dex { - orderbook_model::orderbook_model(kind orderbook_kind, QObject* parent) : QAbstractListModel(parent), m_current_orderbook_kind(orderbook_kind) + orderbook_model::orderbook_model(t_orderbook_answer& orderbook, kind orderbook_kind, QObject* parent) : + QAbstractListModel(parent), m_current_orderbook_kind(orderbook_kind), m_model_data(orderbook) { spdlog::trace("{} l{} f[{}]", __FUNCTION__, __LINE__, fs::path(__FILE__).filename().string()); spdlog::trace("orderbook model created"); @@ -37,7 +38,7 @@ namespace atomic_dex int orderbook_model::rowCount([[maybe_unused]] const QModelIndex& parent) const { - return m_current_orderbook_kind == kind::asks ? m_model_data->asks.size() : m_model_data->bids.size(); + return m_current_orderbook_kind == kind::asks ? m_model_data.asks.size() : m_model_data.bids.size(); } QVariant @@ -50,14 +51,14 @@ namespace atomic_dex switch (static_cast(role)) { case PriceRole: - return m_current_orderbook_kind == kind::asks ? QString::fromStdString(m_model_data->asks.at(index.row()).price) - : QString::fromStdString(m_model_data->bids.at(index.row()).price); + return m_current_orderbook_kind == kind::asks ? QString::fromStdString(m_model_data.asks.at(index.row()).price) + : QString::fromStdString(m_model_data.bids.at(index.row()).price); case QuantityRole: - return m_current_orderbook_kind == kind::asks ? QString::fromStdString(m_model_data->asks.at(index.row()).maxvolume) - : QString::fromStdString(m_model_data->bids.at(index.row()).maxvolume); + return m_current_orderbook_kind == kind::asks ? QString::fromStdString(m_model_data.asks.at(index.row()).maxvolume) + : QString::fromStdString(m_model_data.bids.at(index.row()).maxvolume); case TotalRole: - return m_current_orderbook_kind == kind::asks ? QString::fromStdString(m_model_data->asks.at(index.row()).total) - : QString::fromStdString(m_model_data->bids.at(index.row()).total); + return m_current_orderbook_kind == kind::asks ? QString::fromStdString(m_model_data.asks.at(index.row()).total) + : QString::fromStdString(m_model_data.bids.at(index.row()).total); } } @@ -67,4 +68,12 @@ namespace atomic_dex return {{PriceRole, "price"}, {QuantityRole, "quantity"}, {TotalRole, "total"}}; } + void + orderbook_model::reset_orderbook(t_orderbook_answer& orderbook) noexcept + { + this->beginResetModel(); + m_model_data = orderbook; + this->endResetModel(); + } + } // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.orderbook.model.hpp b/src/atomic.dex.qt.orderbook.model.hpp index ad1073069c..bd469a9255 100644 --- a/src/atomic.dex.qt.orderbook.model.hpp +++ b/src/atomic.dex.qt.orderbook.model.hpp @@ -38,15 +38,16 @@ namespace atomic_dex TotalRole }; - orderbook_model(kind orderbook_kind, QObject* parent = nullptr); + orderbook_model(t_orderbook_answer& orderbook, kind orderbook_kind, QObject* parent = nullptr); ~orderbook_model() noexcept final; [[nodiscard]] int rowCount(const QModelIndex& parent = QModelIndex()) const final; [[nodiscard]] QVariant data(const QModelIndex& index, int role) const final; [[nodiscard]] QHash roleNames() const final; + void reset_orderbook(t_orderbook_answer& orderbook) noexcept; private: kind m_current_orderbook_kind{kind::asks}; - t_orderbook_answer* m_model_data; + t_orderbook_answer& m_model_data; }; } // namespace atomic_dex \ No newline at end of file From 2489e851519d4a5f96cffbc26c99836229c94e24 Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 28 Jul 2020 17:08:54 +0300 Subject: [PATCH 016/515] feat(gui): make sure sell box has enough space --- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index c86276c7dd..398eec6b13 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -420,8 +420,6 @@ Item { anchors.left: parent.left anchors.right: parent.right anchors.top: parent.top - anchors.bottom: parent.verticalCenter - anchors.bottomMargin: layout_margin*0.5 my_side: true } @@ -431,9 +429,9 @@ Item { id: form_rel anchors.left: parent.left anchors.right: parent.right - anchors.top: parent.verticalCenter + anchors.top: form_base.bottom anchors.bottom: parent.bottom - anchors.topMargin: form_base.anchors.bottomMargin + anchors.topMargin: layout_margin field.enabled: enabled && !orderIsSelected() } From 8606fe89f7f956067bd24bf14fc9992db5a2827b Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 28 Jul 2020 17:27:11 +0300 Subject: [PATCH 017/515] feat(gui): fix chart line was not updating at window size change --- atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml b/atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml index 6f1edfc71f..caa32de825 100644 --- a/atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml +++ b/atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml @@ -77,6 +77,8 @@ Item { backgroundColor: chart.backgroundColor plotArea: Qt.rect(chart.plotArea.x, 0, chart.plotArea.width, height) + onHeightChanged: series.updateLastValueY() + CandlestickSeries { id: series_area From cea1fcf576bddfbbee3eec4051dd05f1b17c567f Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 28 Jul 2020 17:43:41 +0300 Subject: [PATCH 018/515] feat(gui): initialize the orderbook layout --- .../qml/Exchange/Trade/Orderbook.qml | 129 ++++++++++++++++++ atomic_qt_design/qml/Exchange/Trade/Trade.qml | 31 ++++- qml.qrc | 1 + 3 files changed, 154 insertions(+), 7 deletions(-) create mode 100644 atomic_qt_design/qml/Exchange/Trade/Orderbook.qml diff --git a/atomic_qt_design/qml/Exchange/Trade/Orderbook.qml b/atomic_qt_design/qml/Exchange/Trade/Orderbook.qml new file mode 100644 index 0000000000..43ba190b43 --- /dev/null +++ b/atomic_qt_design/qml/Exchange/Trade/Orderbook.qml @@ -0,0 +1,129 @@ +import QtQuick 2.12 +import QtQuick.Layouts 1.12 +import QtQuick.Controls 2.12 + +import "../../Components" +import "../../Constants" + +// Open Enable Coin Modal +FloatingBackground { + ColumnLayout { + anchors.fill: parent + + function chooseOrder(order) { + // Choose this order + selectOrder(order) + } + +// // List header +// Item { +// Layout.alignment: Qt.AlignTop + +// Layout.fillWidth: true + +// height: 50 + +// // Price +// DefaultText { +// id: price_header +// anchors.right: parent.right +// anchors.rightMargin: parent.width * 0.77 + +// text_value: API.get().empty_string + (qsTr("Price")) +// color: Style.colorWhite1 +// anchors.verticalCenter: parent.verticalCenter +// } + +// // Volume +// DefaultText { +// id: volume_header +// anchors.right: parent.right +// anchors.rightMargin: parent.width * 0.44 + +// text_value: API.get().empty_string + (qsTr("Volume")) +// color: Style.colorWhite1 +// anchors.verticalCenter: parent.verticalCenter +// } + +// // Receive amount +// DefaultText { +// id: receive_header +// anchors.right: parent.right +// anchors.rightMargin: parent.width * 0.11 + +// text_value: API.get().empty_string + (qsTr("Receive")) +// color: Style.colorWhite1 +// anchors.verticalCenter: parent.verticalCenter +// } + +// // Line +// HorizontalLine { +// width: parent.width +// color: Style.colorWhite5 +// anchors.bottom: parent.bottom +// } +// } + + // List + DefaultListView { + id: list + Layout.alignment: Qt.AlignTop + Layout.fillWidth: true + Layout.fillHeight: true + + model: getCurrentOrderbook().sort((a, b) => parseFloat(b.price) - parseFloat(a.price)) + + delegate: Rectangle { + color: mouse_area.containsMouse ? Style.colorTheme4 : "transparent" + + width: modal_layout.width + height: 50 + + MouseArea { + id: mouse_area + anchors.fill: parent + hoverEnabled: true + onClicked: chooseOrder(model.modelData) + } + + // Price + DefaultText { + anchors.right: parent.right + anchors.rightMargin: price_header.anchors.rightMargin + + text_value: API.get().empty_string + (General.formatDouble(model.modelData.price)) + color: Style.colorWhite4 + anchors.verticalCenter: parent.verticalCenter + } + + // Volume + DefaultText { + anchors.right: parent.right + anchors.rightMargin: volume_header.anchors.rightMargin + + text_value: API.get().empty_string + (model.modelData.volume) + color: Style.colorWhite4 + anchors.verticalCenter: parent.verticalCenter + } + + // Receive amount + DefaultText { + anchors.right: parent.right + anchors.rightMargin: receive_header.anchors.rightMargin + + text_value: API.get().empty_string + (getReceiveAmount(model.modelData.price, model.modelData.volume) + " " + getTicker()) + color: Style.colorWhite4 + anchors.verticalCenter: parent.verticalCenter + } + + // Line + HorizontalLine { + visible: index !== getCurrentOrderbook().length - 1 + width: parent.width + color: Style.colorWhite9 + anchors.bottom: parent.bottom + } + } + } + } +} diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index 398eec6b13..9296e7570f 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -389,20 +389,37 @@ Item { Layout.fillHeight: true Layout.bottomMargin: layout_margin - InnerBackground { - id: graph_bg - + Item { + id: left_section anchors.left: parent.left anchors.right: forms.left anchors.top: parent.top anchors.bottom: parent.bottom anchors.rightMargin: layout_margin - visible: chart.pair_supported + InnerBackground { + id: graph_bg + + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: orderbook.top + anchors.bottomMargin: layout_margin + + visible: chart.pair_supported + + CandleStickChart { + id: chart + anchors.fill: parent + } + } - CandleStickChart { - id: chart - anchors.fill: parent + Orderbook { + id: orderbook + height: 250 + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom } } diff --git a/qml.qrc b/qml.qrc index c803f4760a..e486b08533 100644 --- a/qml.qrc +++ b/qml.qrc @@ -109,6 +109,7 @@ atomic_qt_design/qml/Exchange/Trade/OrderForm.qml atomic_qt_design/qml/Exchange/Trade/OrderReceiveModal.qml atomic_qt_design/qml/Exchange/Trade/OrderbookModal.qml + atomic_qt_design/qml/Exchange/Trade/Orderbook.qml atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml atomic_qt_design/qml/Exchange/Orders/Orders.qml atomic_qt_design/qml/Exchange/Orders/OrderList.qml From 519eed701443250d30a84c74003098c3ec1201b1 Mon Sep 17 00:00:00 2001 From: milerius Date: Tue, 28 Jul 2020 17:01:13 +0200 Subject: [PATCH 019/515] feat(orderbook): using keyword signals --- src/atomic.dex.qt.orderbook.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/atomic.dex.qt.orderbook.hpp b/src/atomic.dex.qt.orderbook.hpp index 05599b6c7c..4330ddd09d 100644 --- a/src/atomic.dex.qt.orderbook.hpp +++ b/src/atomic.dex.qt.orderbook.hpp @@ -41,7 +41,7 @@ namespace atomic_dex [[nodiscard]] orderbook_model* get_asks() const noexcept; [[nodiscard]] orderbook_model* get_bids() const noexcept; - public: + signals: void asksChanged(); void bidsChanged(); From b050e7df00f76f7bdaea9bbba8c61110c317e7ad Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 28 Jul 2020 18:11:34 +0300 Subject: [PATCH 020/515] feat(gui): start adding asks and bids sections --- .../qml/Exchange/Trade/Orderbook.qml | 121 ++---------------- .../qml/Exchange/Trade/OrderbookSection.qml | 121 ++++++++++++++++++ qml.qrc | 1 + 3 files changed, 133 insertions(+), 110 deletions(-) create mode 100644 atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml diff --git a/atomic_qt_design/qml/Exchange/Trade/Orderbook.qml b/atomic_qt_design/qml/Exchange/Trade/Orderbook.qml index 43ba190b43..10eb004c65 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Orderbook.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Orderbook.qml @@ -7,123 +7,24 @@ import "../../Constants" // Open Enable Coin Modal FloatingBackground { - ColumnLayout { + RowLayout { anchors.fill: parent + spacing: 0 - function chooseOrder(order) { - // Choose this order - selectOrder(order) + OrderbookSection { + Layout.fillWidth: true + Layout.fillHeight: true + model: API.get().orderbook.asks } -// // List header -// Item { -// Layout.alignment: Qt.AlignTop - -// Layout.fillWidth: true - -// height: 50 - -// // Price -// DefaultText { -// id: price_header -// anchors.right: parent.right -// anchors.rightMargin: parent.width * 0.77 - -// text_value: API.get().empty_string + (qsTr("Price")) -// color: Style.colorWhite1 -// anchors.verticalCenter: parent.verticalCenter -// } - -// // Volume -// DefaultText { -// id: volume_header -// anchors.right: parent.right -// anchors.rightMargin: parent.width * 0.44 - -// text_value: API.get().empty_string + (qsTr("Volume")) -// color: Style.colorWhite1 -// anchors.verticalCenter: parent.verticalCenter -// } - -// // Receive amount -// DefaultText { -// id: receive_header -// anchors.right: parent.right -// anchors.rightMargin: parent.width * 0.11 - -// text_value: API.get().empty_string + (qsTr("Receive")) -// color: Style.colorWhite1 -// anchors.verticalCenter: parent.verticalCenter -// } - -// // Line -// HorizontalLine { -// width: parent.width -// color: Style.colorWhite5 -// anchors.bottom: parent.bottom -// } -// } + VerticalLine { + Layout.fillHeight: true + } - // List - DefaultListView { - id: list - Layout.alignment: Qt.AlignTop + OrderbookSection { Layout.fillWidth: true Layout.fillHeight: true - - model: getCurrentOrderbook().sort((a, b) => parseFloat(b.price) - parseFloat(a.price)) - - delegate: Rectangle { - color: mouse_area.containsMouse ? Style.colorTheme4 : "transparent" - - width: modal_layout.width - height: 50 - - MouseArea { - id: mouse_area - anchors.fill: parent - hoverEnabled: true - onClicked: chooseOrder(model.modelData) - } - - // Price - DefaultText { - anchors.right: parent.right - anchors.rightMargin: price_header.anchors.rightMargin - - text_value: API.get().empty_string + (General.formatDouble(model.modelData.price)) - color: Style.colorWhite4 - anchors.verticalCenter: parent.verticalCenter - } - - // Volume - DefaultText { - anchors.right: parent.right - anchors.rightMargin: volume_header.anchors.rightMargin - - text_value: API.get().empty_string + (model.modelData.volume) - color: Style.colorWhite4 - anchors.verticalCenter: parent.verticalCenter - } - - // Receive amount - DefaultText { - anchors.right: parent.right - anchors.rightMargin: receive_header.anchors.rightMargin - - text_value: API.get().empty_string + (getReceiveAmount(model.modelData.price, model.modelData.volume) + " " + getTicker()) - color: Style.colorWhite4 - anchors.verticalCenter: parent.verticalCenter - } - - // Line - HorizontalLine { - visible: index !== getCurrentOrderbook().length - 1 - width: parent.width - color: Style.colorWhite9 - anchors.bottom: parent.bottom - } - } + model: API.get().orderbook.bids } } } diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml new file mode 100644 index 0000000000..160575a745 --- /dev/null +++ b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml @@ -0,0 +1,121 @@ +import QtQuick 2.12 +import QtQuick.Layouts 1.12 +import QtQuick.Controls 2.12 + +import "../../Components" +import "../../Constants" + +// Open Enable Coin Modal +ColumnLayout { + property alias model: list.model + function chooseOrder(order) { + // Choose this order + selectOrder(order) + } + + // List header + Item { + Layout.fillWidth: true + + height: 50 + + // Price + DefaultText { + id: price_header + anchors.right: parent.right + anchors.rightMargin: parent.width * 0.77 + + text_value: API.get().empty_string + (qsTr("Price")) + color: Style.colorWhite1 + anchors.verticalCenter: parent.verticalCenter + } + + // Volume + DefaultText { + id: quantity_header + anchors.right: parent.right + anchors.rightMargin: parent.width * 0.44 + + text_value: API.get().empty_string + (qsTr("Volume")) + color: Style.colorWhite1 + anchors.verticalCenter: parent.verticalCenter + } + + // Receive amount + DefaultText { + id: total_header + anchors.right: parent.right + anchors.rightMargin: parent.width * 0.11 + + text_value: API.get().empty_string + (qsTr("Total")) + color: Style.colorWhite1 + anchors.verticalCenter: parent.verticalCenter + } + + // Line + HorizontalLine { + width: parent.width + color: Style.colorWhite5 + anchors.bottom: parent.bottom + } + } + + // List + DefaultListView { + id: list + Layout.fillWidth: true + Layout.fillHeight: true + + delegate: Rectangle { + color: mouse_area.containsMouse ? Style.colorTheme4 : "transparent" + + width: modal_layout.width + height: 50 + + MouseArea { + id: mouse_area + anchors.fill: parent + hoverEnabled: true + //onClicked: chooseOrder(model.modelData) + } + + // Price + DefaultText { + anchors.right: parent.right + anchors.rightMargin: price_header.anchors.rightMargin + + text_value: API.get().empty_string + (General.formatDouble(price)) + color: Style.colorWhite4 + anchors.verticalCenter: parent.verticalCenter + } + + // Quantity + DefaultText { + anchors.right: parent.right + anchors.rightMargin: quantity_header.anchors.rightMargin + + text_value: API.get().empty_string + (quantity) + color: Style.colorWhite4 + anchors.verticalCenter: parent.verticalCenter + } + + // Receive amount + DefaultText { + anchors.right: parent.right + anchors.rightMargin: total_header.anchors.rightMargin + + text_value: API.get().empty_string + (getReceiveAmount(price, quantity) + " " + getTicker()) + color: Style.colorWhite4 + anchors.verticalCenter: parent.verticalCenter + } + + // Line + HorizontalLine { + visible: index !== getCurrentOrderbook().length - 1 + width: parent.width + color: Style.colorWhite9 + anchors.bottom: parent.bottom + } + } + } +} diff --git a/qml.qrc b/qml.qrc index e486b08533..b4c5354d76 100644 --- a/qml.qrc +++ b/qml.qrc @@ -108,6 +108,7 @@ atomic_qt_design/qml/Exchange/Trade/PriceLine.qml atomic_qt_design/qml/Exchange/Trade/OrderForm.qml atomic_qt_design/qml/Exchange/Trade/OrderReceiveModal.qml + atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml atomic_qt_design/qml/Exchange/Trade/OrderbookModal.qml atomic_qt_design/qml/Exchange/Trade/Orderbook.qml atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml From 624036f0632bad26db4ad39ad6fc28affa7d1739 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Tue, 28 Jul 2020 17:22:43 +0200 Subject: [PATCH 021/515] enhancements(orderbook): fix undeclared orderbook in meta type Signed-off-by: romanszterg --- src/atomic.dex.qt.orderbook.hpp | 7 +++++-- src/atomic.dex.qt.orderbook.model.hpp | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/atomic.dex.qt.orderbook.hpp b/src/atomic.dex.qt.orderbook.hpp index 4330ddd09d..65b457c803 100644 --- a/src/atomic.dex.qt.orderbook.hpp +++ b/src/atomic.dex.qt.orderbook.hpp @@ -25,13 +25,16 @@ //! Project #include "atomic.dex.qt.orderbook.model.hpp" +using orderbook_ptr = atomic_dex::orderbook_model*; +Q_DECLARE_METATYPE(orderbook_ptr) + namespace atomic_dex { class qt_orderbook_wrapper final : public QObject { Q_OBJECT - Q_PROPERTY(orderbook_model* asks READ get_asks NOTIFY asksChanged) - Q_PROPERTY(orderbook_model* bids READ get_bids NOTIFY bidsChanged) + Q_PROPERTY(orderbook_ptr asks READ get_asks MEMBER m_asks NOTIFY asksChanged) + Q_PROPERTY(orderbook_ptr bids READ get_bids MEMBER m_bids NOTIFY bidsChanged) public: qt_orderbook_wrapper(ag::ecs::system_manager& system_manager, QObject* parent = nullptr); ~qt_orderbook_wrapper() noexcept final; diff --git a/src/atomic.dex.qt.orderbook.model.hpp b/src/atomic.dex.qt.orderbook.model.hpp index bd469a9255..8641b0fde0 100644 --- a/src/atomic.dex.qt.orderbook.model.hpp +++ b/src/atomic.dex.qt.orderbook.model.hpp @@ -50,4 +50,5 @@ namespace atomic_dex kind m_current_orderbook_kind{kind::asks}; t_orderbook_answer& m_model_data; }; + } // namespace atomic_dex \ No newline at end of file From 5b47d53dc1abcfe25990de4e42edd3e26c1bc95e Mon Sep 17 00:00:00 2001 From: romanszterg Date: Tue, 28 Jul 2020 17:25:53 +0200 Subject: [PATCH 022/515] enhancements(orderbook): fix undeclared orderbook in meta type Signed-off-by: romanszterg --- src/atomic.dex.qt.orderbook.hpp | 7 ++----- src/atomic.dex.qt.orderbook.model.hpp | 1 + 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/atomic.dex.qt.orderbook.hpp b/src/atomic.dex.qt.orderbook.hpp index 65b457c803..a2d88cce4b 100644 --- a/src/atomic.dex.qt.orderbook.hpp +++ b/src/atomic.dex.qt.orderbook.hpp @@ -25,16 +25,13 @@ //! Project #include "atomic.dex.qt.orderbook.model.hpp" -using orderbook_ptr = atomic_dex::orderbook_model*; -Q_DECLARE_METATYPE(orderbook_ptr) - namespace atomic_dex { class qt_orderbook_wrapper final : public QObject { Q_OBJECT - Q_PROPERTY(orderbook_ptr asks READ get_asks MEMBER m_asks NOTIFY asksChanged) - Q_PROPERTY(orderbook_ptr bids READ get_bids MEMBER m_bids NOTIFY bidsChanged) + Q_PROPERTY(orderbook_model* asks READ get_asks MEMBER m_asks NOTIFY asksChanged) + Q_PROPERTY(orderbook_model* bids READ get_bids MEMBER m_bids NOTIFY bidsChanged) public: qt_orderbook_wrapper(ag::ecs::system_manager& system_manager, QObject* parent = nullptr); ~qt_orderbook_wrapper() noexcept final; diff --git a/src/atomic.dex.qt.orderbook.model.hpp b/src/atomic.dex.qt.orderbook.model.hpp index 8641b0fde0..61f2b5a8f0 100644 --- a/src/atomic.dex.qt.orderbook.model.hpp +++ b/src/atomic.dex.qt.orderbook.model.hpp @@ -24,6 +24,7 @@ namespace atomic_dex { class orderbook_model final : public QAbstractListModel { + Q_OBJECT public: enum class kind { From f3293cffaef7558bc556a08e3c3295ee431678fe Mon Sep 17 00:00:00 2001 From: romanszterg Date: Tue, 28 Jul 2020 17:28:52 +0200 Subject: [PATCH 023/515] enhancements(orderbook): add list length Signed-off-by: romanszterg --- src/atomic.dex.qt.orderbook.model.cpp | 7 +++++++ src/atomic.dex.qt.orderbook.model.hpp | 9 +++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/atomic.dex.qt.orderbook.model.cpp b/src/atomic.dex.qt.orderbook.model.cpp index 5ae1fe42d8..4dd33841cd 100644 --- a/src/atomic.dex.qt.orderbook.model.cpp +++ b/src/atomic.dex.qt.orderbook.model.cpp @@ -74,6 +74,13 @@ namespace atomic_dex this->beginResetModel(); m_model_data = orderbook; this->endResetModel(); + emit lengthChanged(); + } + + int + orderbook_model::get_length() const noexcept + { + return rowCount(); } } // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.orderbook.model.hpp b/src/atomic.dex.qt.orderbook.model.hpp index 61f2b5a8f0..cbb64beeaa 100644 --- a/src/atomic.dex.qt.orderbook.model.hpp +++ b/src/atomic.dex.qt.orderbook.model.hpp @@ -24,7 +24,8 @@ namespace atomic_dex { class orderbook_model final : public QAbstractListModel { - Q_OBJECT + Q_OBJECT + Q_PROPERTY(int length READ get_length NOTIFY lengthChanged) public: enum class kind { @@ -46,7 +47,11 @@ namespace atomic_dex [[nodiscard]] QVariant data(const QModelIndex& index, int role) const final; [[nodiscard]] QHash roleNames() const final; - void reset_orderbook(t_orderbook_answer& orderbook) noexcept; + void reset_orderbook(t_orderbook_answer& orderbook) noexcept; + [[nodiscard]] int get_length() const noexcept; + signals: + void lengthChanged(); + private: kind m_current_orderbook_kind{kind::asks}; t_orderbook_answer& m_model_data; From 6cf7217ae3b1588da71305e4b6fd93d6e247c3df Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 28 Jul 2020 18:31:03 +0300 Subject: [PATCH 024/515] feat(gui): implement orderbook --- .../qml/Exchange/Trade/Orderbook.qml | 26 ++++++++++++------- .../qml/Exchange/Trade/OrderbookSection.qml | 16 +++++++----- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/Orderbook.qml b/atomic_qt_design/qml/Exchange/Trade/Orderbook.qml index 10eb004c65..413ee0b0ee 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Orderbook.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Orderbook.qml @@ -7,24 +7,32 @@ import "../../Constants" // Open Enable Coin Modal FloatingBackground { - RowLayout { + Item { anchors.fill: parent - spacing: 0 OrderbookSection { - Layout.fillWidth: true - Layout.fillHeight: true - model: API.get().orderbook.asks + anchors.left: parent.left + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: separator.left + model: API.get().orderbook.bids } VerticalLine { - Layout.fillHeight: true + id: separator + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: parent.top + anchors.bottom: parent.bottom } OrderbookSection { - Layout.fillWidth: true - Layout.fillHeight: true - model: API.get().orderbook.bids + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: separator.right + + is_asks: true + model: API.get().orderbook.asks } } } diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml index 160575a745..4837387cce 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml @@ -7,6 +7,9 @@ import "../../Constants" // Open Enable Coin Modal ColumnLayout { + id: root + + property bool is_asks: false property alias model: list.model function chooseOrder(order) { // Choose this order @@ -41,7 +44,7 @@ ColumnLayout { anchors.verticalCenter: parent.verticalCenter } - // Receive amount + // Total DefaultText { id: total_header anchors.right: parent.right @@ -63,13 +66,14 @@ ColumnLayout { // List DefaultListView { id: list + Layout.fillWidth: true Layout.fillHeight: true delegate: Rectangle { color: mouse_area.containsMouse ? Style.colorTheme4 : "transparent" - width: modal_layout.width + width: root.width height: 50 MouseArea { @@ -85,7 +89,7 @@ ColumnLayout { anchors.rightMargin: price_header.anchors.rightMargin text_value: API.get().empty_string + (General.formatDouble(price)) - color: Style.colorWhite4 + color: is_asks ? Style.colorRed : Style.colorGreen anchors.verticalCenter: parent.verticalCenter } @@ -99,19 +103,19 @@ ColumnLayout { anchors.verticalCenter: parent.verticalCenter } - // Receive amount + // Total DefaultText { anchors.right: parent.right anchors.rightMargin: total_header.anchors.rightMargin - text_value: API.get().empty_string + (getReceiveAmount(price, quantity) + " " + getTicker()) + text_value: API.get().empty_string + (total) color: Style.colorWhite4 anchors.verticalCenter: parent.verticalCenter } // Line HorizontalLine { - visible: index !== getCurrentOrderbook().length - 1 + visible: index !== model.length - 1 width: parent.width color: Style.colorWhite9 anchors.bottom: parent.bottom From 011482fefd4e96b344735a12d5bef92b92c5233d Mon Sep 17 00:00:00 2001 From: romanszterg Date: Tue, 28 Jul 2020 17:39:23 +0200 Subject: [PATCH 025/515] enhancements(orderbook): add UUID Signed-off-by: romanszterg --- src/atomic.dex.mm2.api.cpp | 1 + src/atomic.dex.mm2.api.hpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/atomic.dex.mm2.api.cpp b/src/atomic.dex.mm2.api.cpp index 880a55ebef..318ccceed2 100644 --- a/src/atomic.dex.mm2.api.cpp +++ b/src/atomic.dex.mm2.api.cpp @@ -408,6 +408,7 @@ namespace mm2::api j.at("pubkey").get_to(contents.pubkey); j.at("age").get_to(contents.age); j.at("zcredits").get_to(contents.zcredits); + j.at("uuid").get_to(contents.uuid); if (contents.price.find('.') != std::string::npos) { diff --git a/src/atomic.dex.mm2.api.hpp b/src/atomic.dex.mm2.api.hpp index eb30091845..8595f77624 100644 --- a/src/atomic.dex.mm2.api.hpp +++ b/src/atomic.dex.mm2.api.hpp @@ -389,6 +389,7 @@ namespace mm2::api std::size_t age; std::size_t zcredits; std::string total; + std::string uuid; }; void from_json(const nlohmann::json& j, order_contents& contents); From 8c1d6796b2aaaa176609a1a7d6dfc8566c39213a Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 28 Jul 2020 18:41:26 +0300 Subject: [PATCH 026/515] feat(gui): display order count --- atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml index 4837387cce..ae4d41a2e8 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml @@ -28,7 +28,7 @@ ColumnLayout { anchors.right: parent.right anchors.rightMargin: parent.width * 0.77 - text_value: API.get().empty_string + (qsTr("Price")) + text_value: API.get().empty_string + (qsTr("Price") + " (" + model.length + ")") color: Style.colorWhite1 anchors.verticalCenter: parent.verticalCenter } @@ -115,7 +115,7 @@ ColumnLayout { // Line HorizontalLine { - visible: index !== model.length - 1 + visible: index !== root.model.length - 1 width: parent.width color: Style.colorWhite9 anchors.bottom: parent.bottom From 0a3de3010a1f2c93252c22efd00c165a6ca9b5ee Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 28 Jul 2020 18:46:42 +0300 Subject: [PATCH 027/515] feat(gui): add asks/bids titles --- .../qml/Exchange/Trade/OrderbookSection.qml | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml index ae4d41a2e8..29fa2e1c5a 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml @@ -22,13 +22,27 @@ ColumnLayout { height: 50 + DefaultText { + id: title + anchors.top: parent.top + anchors.topMargin: 4 + anchors.right: is_asks ? undefined : parent.right + anchors.rightMargin: is_asks ? undefined : anchors.topMargin + anchors.left: is_asks ? undefined : parent.left + anchors.leftMargin: is_asks ? undefined : anchors.topMargin + + text_value: API.get().empty_string + ((is_asks ? qsTr("Asks") : qsTr("Bids")) + " (" + model.length + ")") + color: is_asks ? Style.colorRed : Style.colorGreen + anchors.verticalCenter: parent.verticalCenter + } + // Price DefaultText { id: price_header anchors.right: parent.right anchors.rightMargin: parent.width * 0.77 - text_value: API.get().empty_string + (qsTr("Price") + " (" + model.length + ")") + text_value: API.get().empty_string + (qsTr("Price")) color: Style.colorWhite1 anchors.verticalCenter: parent.verticalCenter } @@ -89,7 +103,7 @@ ColumnLayout { anchors.rightMargin: price_header.anchors.rightMargin text_value: API.get().empty_string + (General.formatDouble(price)) - color: is_asks ? Style.colorRed : Style.colorGreen + color: title.color anchors.verticalCenter: parent.verticalCenter } From 33e15fc72568c57bc2dd461e58457d007c04f250 Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 28 Jul 2020 18:53:25 +0300 Subject: [PATCH 028/515] feat(gui): positioning orderbook titles --- .../qml/Exchange/Trade/OrderbookSection.qml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml index 29fa2e1c5a..5a1cc266e5 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml @@ -25,11 +25,11 @@ ColumnLayout { DefaultText { id: title anchors.top: parent.top - anchors.topMargin: 4 - anchors.right: is_asks ? undefined : parent.right - anchors.rightMargin: is_asks ? undefined : anchors.topMargin - anchors.left: is_asks ? undefined : parent.left - anchors.leftMargin: is_asks ? undefined : anchors.topMargin + anchors.topMargin: 8 + anchors.left: parent.left + anchors.leftMargin: anchors.topMargin + + font.pixelSize: Style.textSizeSmall2 text_value: API.get().empty_string + ((is_asks ? qsTr("Asks") : qsTr("Bids")) + " (" + model.length + ")") color: is_asks ? Style.colorRed : Style.colorGreen From f1f7a889dd18003e965639b47c1b46d34164ea17 Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 28 Jul 2020 18:57:10 +0300 Subject: [PATCH 029/515] feat(gui): no chart data warning --- atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml | 8 +++++++- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 3 --- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml b/atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml index caa32de825..66df3ed1e2 100644 --- a/atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml +++ b/atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml @@ -630,7 +630,13 @@ Item { } DefaultBusyIndicator { - visible: !chart.visible + visible: pair_supported && !chart.visible + anchors.centerIn: parent + } + + DefaultText { + visible: !pair_supported + text_value: API.get().empty_string + (qsTr("We don't have chart data for this pair yet")) anchors.centerIn: parent } } diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index 9296e7570f..ebbcfcaeb5 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -406,10 +406,7 @@ Item { anchors.bottom: orderbook.top anchors.bottomMargin: layout_margin - visible: chart.pair_supported - CandleStickChart { - id: chart anchors.fill: parent } } From 1d75b5ae68b42bb3ca480a7108770dd9bfccdadc Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 28 Jul 2020 19:02:11 +0300 Subject: [PATCH 030/515] feat(gui): smaller orderbook text size --- .../qml/Exchange/Trade/OrderbookSection.qml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml index 5a1cc266e5..b18ff98f62 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml @@ -42,6 +42,8 @@ ColumnLayout { anchors.right: parent.right anchors.rightMargin: parent.width * 0.77 + font.pixelSize: Style.textSizeSmall2 + text_value: API.get().empty_string + (qsTr("Price")) color: Style.colorWhite1 anchors.verticalCenter: parent.verticalCenter @@ -53,6 +55,8 @@ ColumnLayout { anchors.right: parent.right anchors.rightMargin: parent.width * 0.44 + font.pixelSize: price_header.font.pixelSize + text_value: API.get().empty_string + (qsTr("Volume")) color: Style.colorWhite1 anchors.verticalCenter: parent.verticalCenter @@ -64,6 +68,8 @@ ColumnLayout { anchors.right: parent.right anchors.rightMargin: parent.width * 0.11 + font.pixelSize: price_header.font.pixelSize + text_value: API.get().empty_string + (qsTr("Total")) color: Style.colorWhite1 anchors.verticalCenter: parent.verticalCenter @@ -99,9 +105,12 @@ ColumnLayout { // Price DefaultText { + id: price_value anchors.right: parent.right anchors.rightMargin: price_header.anchors.rightMargin + font.pixelSize: Style.textSizeSmall2 + text_value: API.get().empty_string + (General.formatDouble(price)) color: title.color anchors.verticalCenter: parent.verticalCenter @@ -109,9 +118,12 @@ ColumnLayout { // Quantity DefaultText { + id: quantity_value anchors.right: parent.right anchors.rightMargin: quantity_header.anchors.rightMargin + font.pixelSize: price_value.font.pixelSize + text_value: API.get().empty_string + (quantity) color: Style.colorWhite4 anchors.verticalCenter: parent.verticalCenter @@ -119,9 +131,12 @@ ColumnLayout { // Total DefaultText { + id: total_value anchors.right: parent.right anchors.rightMargin: total_header.anchors.rightMargin + font.pixelSize: price_value.font.pixelSize + text_value: API.get().empty_string + (total) color: Style.colorWhite4 anchors.verticalCenter: parent.verticalCenter From f7eba1661ffe880b0eaeebf89bfec92ce32de31d Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 28 Jul 2020 19:21:10 +0300 Subject: [PATCH 031/515] feat(gui): reposition orderbook headers --- .../qml/Exchange/Trade/OrderbookSection.qml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml index b18ff98f62..9afd8aaa77 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml @@ -26,12 +26,12 @@ ColumnLayout { id: title anchors.top: parent.top anchors.topMargin: 8 - anchors.left: parent.left - anchors.leftMargin: anchors.topMargin + anchors.horizontalCenter: quantity_header.horizontalCenter font.pixelSize: Style.textSizeSmall2 - text_value: API.get().empty_string + ((is_asks ? qsTr("Asks") : qsTr("Bids")) + " (" + model.length + ")") + text_value: API.get().empty_string + ((is_asks ? qsTr("Asks") : qsTr("Bids")) + + " (" + model.length + ")") color: is_asks ? Style.colorRed : Style.colorGreen anchors.verticalCenter: parent.verticalCenter } @@ -47,9 +47,10 @@ ColumnLayout { text_value: API.get().empty_string + (qsTr("Price")) color: Style.colorWhite1 anchors.verticalCenter: parent.verticalCenter + anchors.verticalCenterOffset: parent.height * 0.2 } - // Volume + // Quantity DefaultText { id: quantity_header anchors.right: parent.right @@ -57,9 +58,10 @@ ColumnLayout { font.pixelSize: price_header.font.pixelSize - text_value: API.get().empty_string + (qsTr("Volume")) + text_value: API.get().empty_string + (qsTr("Quantity")) color: Style.colorWhite1 anchors.verticalCenter: parent.verticalCenter + anchors.verticalCenterOffset: price_header.anchors.verticalCenterOffset } // Total @@ -73,6 +75,7 @@ ColumnLayout { text_value: API.get().empty_string + (qsTr("Total")) color: Style.colorWhite1 anchors.verticalCenter: parent.verticalCenter + anchors.verticalCenterOffset: price_header.anchors.verticalCenterOffset } // Line From 2c16b0b2cbd7eb7a55e8aa01aa5f9fc093ea697a Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 28 Jul 2020 19:31:44 +0300 Subject: [PATCH 032/515] feat(gui): smaller orderbook text --- atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml index 9afd8aaa77..42b6b10be8 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml @@ -112,7 +112,7 @@ ColumnLayout { anchors.right: parent.right anchors.rightMargin: price_header.anchors.rightMargin - font.pixelSize: Style.textSizeSmall2 + font.pixelSize: Style.textSizeSmall1 text_value: API.get().empty_string + (General.formatDouble(price)) color: title.color From 7cc3dac077482084489b2e2fc681a0383333f56c Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 28 Jul 2020 20:25:43 +0300 Subject: [PATCH 033/515] feat(gui): symmetrical asks bids sections --- .../qml/Components/DefaultListView.qml | 2 +- atomic_qt_design/qml/Exchange/Exchange.qml | 4 +- .../qml/Exchange/Trade/OrderbookSection.qml | 59 ++++++++++--------- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 1 - 4 files changed, 32 insertions(+), 34 deletions(-) diff --git a/atomic_qt_design/qml/Components/DefaultListView.qml b/atomic_qt_design/qml/Components/DefaultListView.qml index 867175a525..dbcc5fa2d2 100644 --- a/atomic_qt_design/qml/Components/DefaultListView.qml +++ b/atomic_qt_design/qml/Components/DefaultListView.qml @@ -7,7 +7,7 @@ import "../Constants" ListView { id: root - readonly property bool scrollbar_visible: contentHeight > height + property bool scrollbar_visible: contentHeight > height readonly property double scrollbar_margin: scrollbar_visible ? 8 : 0 ScrollBar.vertical: DefaultScrollBar { } diff --git a/atomic_qt_design/qml/Exchange/Exchange.qml b/atomic_qt_design/qml/Exchange/Exchange.qml index 9adbc4b2a3..3265755ec5 100644 --- a/atomic_qt_design/qml/Exchange/Exchange.qml +++ b/atomic_qt_design/qml/Exchange/Exchange.qml @@ -10,7 +10,7 @@ import "./History" Item { id: exchange - readonly property int layout_margin: 30 + readonly property int layout_margin: 15 property int prev_page: -1 property int current_page: API.design_editor ? General.idx_exchange_trade : General.idx_exchange_trade @@ -77,7 +77,6 @@ Item { Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter Layout.fillWidth: true Layout.topMargin: layout_margin - Layout.leftMargin: layout_margin Layout.rightMargin: layout_margin content: Item { @@ -126,7 +125,6 @@ Item { Layout.fillWidth: true Layout.fillHeight: true Layout.bottomMargin: layout_margin - Layout.leftMargin: Layout.bottomMargin Layout.rightMargin: Layout.bottomMargin currentIndex: current_page diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml index 42b6b10be8..7f7be072f9 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml @@ -22,60 +22,52 @@ ColumnLayout { height: 50 + // Price DefaultText { - id: title - anchors.top: parent.top - anchors.topMargin: 8 - anchors.horizontalCenter: quantity_header.horizontalCenter - + id: price_header font.pixelSize: Style.textSizeSmall2 - text_value: API.get().empty_string + ((is_asks ? qsTr("Asks") : qsTr("Bids")) + - " (" + model.length + ")") - color: is_asks ? Style.colorRed : Style.colorGreen - anchors.verticalCenter: parent.verticalCenter - } + text_value: API.get().empty_string + (is_asks ? qsTr("Ask Price") + " (" + model.length + ")" : + "(" + model.length + ") " + qsTr("Bid Price")) - // Price - DefaultText { - id: price_header - anchors.right: parent.right - anchors.rightMargin: parent.width * 0.77 + color: is_asks ? Style.colorRed : Style.colorGreen - font.pixelSize: Style.textSizeSmall2 + anchors.left: is_asks ? parent.left : undefined + anchors.right: is_asks ? undefined : parent.right + anchors.leftMargin: is_asks ? parent.width * 0.02 : undefined + anchors.rightMargin: is_asks ? undefined : parent.width * 0.02 - text_value: API.get().empty_string + (qsTr("Price")) - color: Style.colorWhite1 anchors.verticalCenter: parent.verticalCenter - anchors.verticalCenterOffset: parent.height * 0.2 } // Quantity DefaultText { id: quantity_header - anchors.right: parent.right - anchors.rightMargin: parent.width * 0.44 + anchors.left: is_asks ? parent.left : undefined + anchors.right: is_asks ? undefined : parent.right + anchors.leftMargin: is_asks ? parent.width * 0.3 : undefined + anchors.rightMargin: is_asks ? undefined : parent.width * 0.3 font.pixelSize: price_header.font.pixelSize text_value: API.get().empty_string + (qsTr("Quantity")) color: Style.colorWhite1 anchors.verticalCenter: parent.verticalCenter - anchors.verticalCenterOffset: price_header.anchors.verticalCenterOffset } // Total DefaultText { id: total_header - anchors.right: parent.right - anchors.rightMargin: parent.width * 0.11 + anchors.left: is_asks ? parent.left : undefined + anchors.right: is_asks ? undefined : parent.right + anchors.leftMargin: is_asks ? parent.width * 0.7 : undefined + anchors.rightMargin: is_asks ? undefined : parent.width * 0.7 font.pixelSize: price_header.font.pixelSize text_value: API.get().empty_string + (qsTr("Total")) color: Style.colorWhite1 anchors.verticalCenter: parent.verticalCenter - anchors.verticalCenterOffset: price_header.anchors.verticalCenterOffset } // Line @@ -90,6 +82,8 @@ ColumnLayout { DefaultListView { id: list + scrollbar_visible: false + Layout.fillWidth: true Layout.fillHeight: true @@ -109,20 +103,25 @@ ColumnLayout { // Price DefaultText { id: price_value - anchors.right: parent.right + + anchors.left: is_asks ? parent.left : undefined + anchors.right: is_asks ? undefined : parent.right + anchors.leftMargin: price_header.anchors.leftMargin anchors.rightMargin: price_header.anchors.rightMargin font.pixelSize: Style.textSizeSmall1 text_value: API.get().empty_string + (General.formatDouble(price)) - color: title.color + color: price_header.color anchors.verticalCenter: parent.verticalCenter } // Quantity DefaultText { id: quantity_value - anchors.right: parent.right + anchors.left: is_asks ? parent.left : undefined + anchors.right: is_asks ? undefined : parent.right + anchors.leftMargin: quantity_header.anchors.leftMargin anchors.rightMargin: quantity_header.anchors.rightMargin font.pixelSize: price_value.font.pixelSize @@ -135,7 +134,9 @@ ColumnLayout { // Total DefaultText { id: total_value - anchors.right: parent.right + anchors.left: is_asks ? parent.left : undefined + anchors.right: is_asks ? undefined : parent.right + anchors.leftMargin: total_header.anchors.leftMargin anchors.rightMargin: total_header.anchors.rightMargin font.pixelSize: price_value.font.pixelSize diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index ebbcfcaeb5..8da56c4e1f 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -10,7 +10,6 @@ Item { id: exchange_trade property string action_result - readonly property int layout_margin: 20 // Override property var onOrderSuccess: () => {} From 10fa648736cfe238ce0e5ed9ef33f6ab901bff03 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Tue, 28 Jul 2020 19:31:47 +0200 Subject: [PATCH 034/515] enhancements(orderbook): fixing orderbook behavior Signed-off-by: romanszterg --- src/atomic.dex.app.cpp | 15 ++- src/atomic.dex.app.hpp | 1 + src/atomic.dex.events.hpp | 7 +- src/atomic.dex.mm2.cpp | 33 +++--- src/atomic.dex.mm2.hpp | 4 +- src/atomic.dex.qt.orderbook.cpp | 25 +++- src/atomic.dex.qt.orderbook.hpp | 3 +- src/atomic.dex.qt.orderbook.model.cpp | 158 +++++++++++++++++++++++++- src/atomic.dex.qt.orderbook.model.hpp | 20 +++- 9 files changed, 226 insertions(+), 40 deletions(-) diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index 9d85109959..5c08790a48 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -293,11 +293,18 @@ namespace atomic_dex case action::post_process_orderbook_finished: if (mm2.is_mm2_running()) { - std::error_code ec; + std::error_code ec; t_orderbook_answer result = this->get_mm2().get_orderbook(ec); if (!ec) { - this->m_orderbook->refresh_orderbook(result); + if (this->m_orderbook_need_a_reset) + { + this->m_orderbook->reset_orderbook(result); + } + else + { + this->m_orderbook->refresh_orderbook(result); + } } } case action::refresh_update_status: @@ -836,6 +843,7 @@ namespace atomic_dex } this->m_orders->clear_registry(); this->m_candlestick_chart_ohlc->clear_data(); + this->m_orderbook->clear_orderbook(); //! Mark systems system_manager_.mark_system(); @@ -1465,11 +1473,12 @@ namespace atomic_dex } void - application::on_process_orderbook_finished_event(const process_orderbook_finished&) noexcept + application::on_process_orderbook_finished_event(const process_orderbook_finished& evt) noexcept { if (not m_about_to_exit_app) { this->m_actions_queue.push(action::post_process_orderbook_finished); + this->m_orderbook_need_a_reset = evt.is_a_reset; } } } // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.app.hpp b/src/atomic.dex.app.hpp index bb98fb2711..f1da9586bd 100644 --- a/src/atomic.dex.app.hpp +++ b/src/atomic.dex.app.hpp @@ -292,6 +292,7 @@ namespace atomic_dex //! Orderbook Model Wrapper qt_orderbook_wrapper* m_orderbook; + std::atomic_bool m_orderbook_need_a_reset{false}; std::atomic_bool m_about_to_exit_app{false}; }; diff --git a/src/atomic.dex.events.hpp b/src/atomic.dex.events.hpp index d4ec1cae35..6767099c71 100644 --- a/src/atomic.dex.events.hpp +++ b/src/atomic.dex.events.hpp @@ -32,7 +32,12 @@ namespace atomic_dex using refresh_update_status = entt::tag<"gui_refresh_update_status"_hs>; using process_orders_finished = entt::tag<"gui_process_orders_finished"_hs>; using process_swaps_finished = entt::tag<"gui_process_swaps_finished"_hs>; - using process_orderbook_finished = entt::tag<"gui_process_orderbook_finished"_hs>; + // using process_orderbook_finished = entt::tag<"gui_process_orderbook_finished"_hs>; + + struct process_orderbook_finished + { + bool is_a_reset; + }; struct refresh_ohlc_needed { diff --git a/src/atomic.dex.mm2.cpp b/src/atomic.dex.mm2.cpp index 4f8de7cbfe..4e2690612e 100644 --- a/src/atomic.dex.mm2.cpp +++ b/src/atomic.dex.mm2.cpp @@ -157,7 +157,7 @@ namespace atomic_dex if (s >= 5s) { - spawn([this]() { fetch_current_orderbook_thread(); }); + spawn([this]() { fetch_current_orderbook_thread(false); }); m_orderbook_clock = std::chrono::high_resolution_clock::now(); } @@ -506,7 +506,7 @@ namespace atomic_dex } void - mm2::process_orderbook() + mm2::process_orderbook(bool is_a_reset) { auto&& [base, rel] = m_synchronized_ticker_pair.get(); t_orderbook_request request{.base = base, .rel = rel}; @@ -514,12 +514,12 @@ namespace atomic_dex if (answer.rpc_result_code not_eq -1) { m_current_orderbook.insert_or_assign(base + "/" + rel, answer); - this->dispatcher_.trigger(); + this->dispatcher_.trigger(is_a_reset); } } void - mm2::fetch_current_orderbook_thread() + mm2::fetch_current_orderbook_thread(bool is_a_reset) { spdlog::info("Fetch current orderbook"); @@ -530,7 +530,7 @@ namespace atomic_dex return; } - process_orderbook(); + process_orderbook(is_a_reset); } void @@ -829,15 +829,15 @@ namespace atomic_dex { tx_infos current_info{ - .am_i_sender = current.my_balance_change[0] == '-', - .confirmations = current.confirmations.has_value() ? current.confirmations.value() : 0, - .from = current.from, - .to = current.to, - .date = current.timestamp_as_date, - .timestamp = current.timestamp, - .tx_hash = current.tx_hash, - .fees = current.fee_details.normal_fees.has_value() ? current.fee_details.normal_fees.value().amount - : current.fee_details.erc_fees.value().total_fee, + .am_i_sender = current.my_balance_change[0] == '-', + .confirmations = current.confirmations.has_value() ? current.confirmations.value() : 0, + .from = current.from, + .to = current.to, + .date = current.timestamp_as_date, + .timestamp = current.timestamp, + .tx_hash = current.tx_hash, + .fees = current.fee_details.normal_fees.has_value() ? current.fee_details.normal_fees.value().amount + : current.fee_details.erc_fees.value().total_fee, .my_balance_change = current.my_balance_change, .total_amount = current.total_amount, .block_height = current.block_height, @@ -864,16 +864,13 @@ namespace atomic_dex spdlog::debug("{} l{} f[{}]", __FUNCTION__, __LINE__, fs::path(__FILE__).filename().string()); spdlog::info("refreshing orderbook pair: [{} / {}]", evt.base, evt.rel); - const auto key = evt.base; - this->m_synchronized_ticker_pair = std::make_pair(evt.base, evt.rel); if (this->m_mm2_running) { spawn([this]() { - // loguru::set_thread_name("r_book thread"); process_fees(); - fetch_current_orderbook_thread(); + fetch_current_orderbook_thread(true); }); } } diff --git a/src/atomic.dex.mm2.hpp b/src/atomic.dex.mm2.hpp index 6c6dff5674..502e5c2ef8 100644 --- a/src/atomic.dex.mm2.hpp +++ b/src/atomic.dex.mm2.hpp @@ -113,7 +113,7 @@ namespace atomic_dex t_swaps_avrg_datas m_swaps_avrg_registry; //! Refresh the current orderbook (internally call process_orderbook) - void fetch_current_orderbook_thread(); + void fetch_current_orderbook_thread(bool is_a_reset = false); //! Refresh the balance registry (internal) void process_balance(const std::string& ticker) const; @@ -125,7 +125,7 @@ namespace atomic_dex void process_fees(); //! Refresh the orderbook registry (internal) - void process_orderbook(); + void process_orderbook(bool is_a_reset = false); public: //! Constructor diff --git a/src/atomic.dex.qt.orderbook.cpp b/src/atomic.dex.qt.orderbook.cpp index a8f76fcbd0..2cfbb0a5e9 100644 --- a/src/atomic.dex.qt.orderbook.cpp +++ b/src/atomic.dex.qt.orderbook.cpp @@ -19,8 +19,8 @@ namespace atomic_dex { qt_orderbook_wrapper::qt_orderbook_wrapper(ag::ecs::system_manager& system_manager, QObject* parent) : - QObject(parent), m_system_manager(system_manager), m_asks(new orderbook_model(m_last_orderbook, orderbook_model::kind::asks, this)), - m_bids(new orderbook_model(m_last_orderbook, orderbook_model::kind::bids, this)) + QObject(parent), m_system_manager(system_manager), m_asks(new orderbook_model( orderbook_model::kind::asks, this)), + m_bids(new orderbook_model(orderbook_model::kind::bids, this)) { spdlog::trace("{} l{} f[{}]", __FUNCTION__, __LINE__, fs::path(__FILE__).filename().string()); spdlog::trace("orderbook wrapper object created"); @@ -47,8 +47,23 @@ namespace atomic_dex void qt_orderbook_wrapper::refresh_orderbook(t_orderbook_answer answer) { - this->m_last_orderbook = std::move(answer); - this->m_asks->reset_orderbook(m_last_orderbook); - this->m_bids->reset_orderbook(m_last_orderbook); + spdlog::trace("refresh orderbook"); + this->m_asks->refresh_orderbook(answer); + this->m_bids->refresh_orderbook(answer); + } + + void + qt_orderbook_wrapper::reset_orderbook(t_orderbook_answer answer) + { + spdlog::trace("full reset orderbook"); + this->m_asks->reset_orderbook(answer); + this->m_bids->reset_orderbook(answer); + } + + void + qt_orderbook_wrapper::clear_orderbook() + { + this->m_asks->clear_orderbook(); + this->m_bids->clear_orderbook(); } } // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.orderbook.hpp b/src/atomic.dex.qt.orderbook.hpp index a2d88cce4b..2166424237 100644 --- a/src/atomic.dex.qt.orderbook.hpp +++ b/src/atomic.dex.qt.orderbook.hpp @@ -38,6 +38,8 @@ namespace atomic_dex public: void refresh_orderbook(t_orderbook_answer answer); + void reset_orderbook(t_orderbook_answer answer); + void clear_orderbook();; [[nodiscard]] orderbook_model* get_asks() const noexcept; [[nodiscard]] orderbook_model* get_bids() const noexcept; @@ -47,7 +49,6 @@ namespace atomic_dex private: ag::ecs::system_manager& m_system_manager; - t_orderbook_answer m_last_orderbook; orderbook_model* m_asks; orderbook_model* m_bids; }; diff --git a/src/atomic.dex.qt.orderbook.model.cpp b/src/atomic.dex.qt.orderbook.model.cpp index 4dd33841cd..4769e27705 100644 --- a/src/atomic.dex.qt.orderbook.model.cpp +++ b/src/atomic.dex.qt.orderbook.model.cpp @@ -20,10 +20,22 @@ //! Project #include "atomic.dex.qt.orderbook.model.hpp" +namespace +{ + template + void + update_value(int role, const TValue& value, const QModelIndex& idx, TModel& model) + { + if (value != model.data(idx, role)) + { + model.setData(idx, value, role); + } + } +} // namespace + namespace atomic_dex { - orderbook_model::orderbook_model(t_orderbook_answer& orderbook, kind orderbook_kind, QObject* parent) : - QAbstractListModel(parent), m_current_orderbook_kind(orderbook_kind), m_model_data(orderbook) + orderbook_model::orderbook_model(kind orderbook_kind, QObject* parent) : QAbstractListModel(parent), m_current_orderbook_kind(orderbook_kind) { spdlog::trace("{} l{} f[{}]", __FUNCTION__, __LINE__, fs::path(__FILE__).filename().string()); spdlog::trace("orderbook model created"); @@ -59,20 +71,60 @@ namespace atomic_dex case TotalRole: return m_current_orderbook_kind == kind::asks ? QString::fromStdString(m_model_data.asks.at(index.row()).total) : QString::fromStdString(m_model_data.bids.at(index.row()).total); + case UUIDRole: + return m_current_orderbook_kind == kind::asks ? QString::fromStdString(m_model_data.asks.at(index.row()).uuid) + : QString::fromStdString(m_model_data.bids.at(index.row()).uuid); + } + } + + bool + orderbook_model::setData(const QModelIndex& index, const QVariant& value, int role) + { + if (!hasIndex(index.row(), index.column(), index.parent()) || !value.isValid()) + { + return false; + } + ::mm2::api::order_contents& order = m_current_orderbook_kind == kind::asks ? m_model_data.asks.at(index.row()) : m_model_data.bids.at(index.row()); + switch (static_cast(role)) + { + case PriceRole: + order.price = value.toString().toStdString(); + break; + case QuantityRole: + order.maxvolume = value.toString().toStdString(); + break; + case TotalRole: + order.total = value.toString().toStdString(); + break; + case UUIDRole: + order.uuid = value.toString().toStdString(); + break; } + emit dataChanged(index, index, {role}); + return true; } QHash orderbook_model::roleNames() const { - return {{PriceRole, "price"}, {QuantityRole, "quantity"}, {TotalRole, "total"}}; + return {{PriceRole, "price"}, {QuantityRole, "quantity"}, {TotalRole, "total"}, {UUIDRole, "uuid"}}; } void - orderbook_model::reset_orderbook(t_orderbook_answer& orderbook) noexcept + orderbook_model::reset_orderbook(const t_orderbook_answer& orderbook) noexcept { this->beginResetModel(); - m_model_data = orderbook; + m_model_data = orderbook; + std::vector<::mm2::api::order_contents>& model_data = this->m_current_orderbook_kind == kind::asks ? this->m_model_data.asks : this->m_model_data.bids; + m_orders_id_registry.clear(); + for (auto&& order: model_data) + { + if (this->m_orders_id_registry.find(order.uuid) == m_orders_id_registry.end()) + { + this->m_orders_id_registry.emplace(order.uuid); + } + } + this->endResetModel(); emit lengthChanged(); } @@ -83,4 +135,100 @@ namespace atomic_dex return rowCount(); } + + void + orderbook_model::initialize_order(const ::mm2::api::order_contents& order) noexcept + { + std::vector<::mm2::api::order_contents>& model_data = this->m_current_orderbook_kind == kind::asks ? this->m_model_data.asks : this->m_model_data.bids; + beginInsertRows(QModelIndex(), model_data.size(), model_data.size()); + model_data.push_back(order); + this->m_orders_id_registry.emplace(order.uuid); + endInsertRows(); + emit lengthChanged(); + } + + void + orderbook_model::update_order(const ::mm2::api::order_contents& order) noexcept + { + if (const auto res = this->match(index(0, 0), UUIDRole, QString::fromStdString(order.uuid)); not res.isEmpty()) + { + //! ID Found, update ! + const QModelIndex& idx = res.at(0); + update_value(OrderbookRoles::PriceRole, QString::fromStdString(order.price), idx, *this); + update_value(OrderbookRoles::QuantityRole, QString::fromStdString(order.maxvolume), idx, *this); + update_value(OrderbookRoles::TotalRole, QString::fromStdString(order.total), idx, *this); + } + } + + void + orderbook_model::refresh_orderbook(const t_orderbook_answer& orderbook) noexcept + { + m_model_data = orderbook; + auto refresh_functor = [this](const std::vector<::mm2::api::order_contents>& contents) { + for (auto&& current_order: contents) + { + if (this->m_orders_id_registry.find(current_order.uuid) != this->m_orders_id_registry.end()) + { + spdlog::trace("updating order id: {}", current_order.uuid); + this->update_order(current_order); + } + else + { + spdlog::trace("inserting id: {}", current_order.uuid); + this->initialize_order(current_order); + } + } + std::unordered_set to_remove; + for (auto&& id: this->m_orders_id_registry) + { + bool res = std::none_of(begin(contents), end(contents), [id](auto&& contents) { return contents.uuid == id; }); + //! Need to remove the row + if (res) + { + auto res_list = this->match(index(0, 0), UUIDRole, QString::fromStdString(id)); + if (not res_list.empty()) + { + spdlog::trace("removing order from orderbook id: {}", id); + this->removeRow(res_list.at(0).row()); + to_remove.emplace(id); + } + } + } + for (auto&& cur_to_remove: to_remove) { m_orders_id_registry.erase(cur_to_remove); } + }; + switch (this->m_current_orderbook_kind) + { + case kind::asks: + refresh_functor(this->m_model_data.asks); + break; + case kind::bids: + refresh_functor(this->m_model_data.bids); + break; + } + } + + bool + orderbook_model::removeRows(int position, int rows, [[maybe_unused]] const QModelIndex& parent) + { + std::vector<::mm2::api::order_contents>& model_data = this->m_current_orderbook_kind == kind::asks ? this->m_model_data.asks : this->m_model_data.bids; + beginRemoveRows(QModelIndex(), position, position + rows - 1); + for (int row = 0; row < rows; ++row) + { + model_data.erase(model_data.begin() + position); + emit lengthChanged(); + } + endRemoveRows(); + + return true; + } + + void + orderbook_model::clear_orderbook() noexcept + { + this->beginResetModel(); + m_model_data = t_orderbook_answer{}; + m_orders_id_registry.clear(); + this->endResetModel(); + emit lengthChanged(); + } } // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.orderbook.model.hpp b/src/atomic.dex.qt.orderbook.model.hpp index cbb64beeaa..759cc5ccf5 100644 --- a/src/atomic.dex.qt.orderbook.model.hpp +++ b/src/atomic.dex.qt.orderbook.model.hpp @@ -37,24 +37,34 @@ namespace atomic_dex { PriceRole, QuantityRole, - TotalRole + TotalRole, + UUIDRole }; - orderbook_model(t_orderbook_answer& orderbook, kind orderbook_kind, QObject* parent = nullptr); + orderbook_model(kind orderbook_kind, QObject* parent = nullptr); ~orderbook_model() noexcept final; [[nodiscard]] int rowCount(const QModelIndex& parent = QModelIndex()) const final; [[nodiscard]] QVariant data(const QModelIndex& index, int role) const final; [[nodiscard]] QHash roleNames() const final; + bool setData(const QModelIndex& index, const QVariant& value, int role) final; + bool removeRows(int row, int count, const QModelIndex& parent) override; - void reset_orderbook(t_orderbook_answer& orderbook) noexcept; + void reset_orderbook(const t_orderbook_answer& orderbook) noexcept; + void refresh_orderbook(const t_orderbook_answer& orderbook) noexcept; + void clear_orderbook() noexcept;; [[nodiscard]] int get_length() const noexcept; signals: void lengthChanged(); private: - kind m_current_orderbook_kind{kind::asks}; - t_orderbook_answer& m_model_data; + void initialize_order(const ::mm2::api::order_contents& order) noexcept; + void update_order(const ::mm2::api::order_contents& order) noexcept; + + private: + kind m_current_orderbook_kind{kind::asks}; + t_orderbook_answer m_model_data; + std::unordered_set m_orders_id_registry; }; } // namespace atomic_dex \ No newline at end of file From 139bccad3190a798eef311a5e443fe9ad09934e4 Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 28 Jul 2020 20:33:50 +0300 Subject: [PATCH 035/515] feat(gui): change orderbook background --- atomic_qt_design/qml/Exchange/Trade/Orderbook.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/Orderbook.qml b/atomic_qt_design/qml/Exchange/Trade/Orderbook.qml index 413ee0b0ee..f98b5015ec 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Orderbook.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Orderbook.qml @@ -6,7 +6,7 @@ import "../../Components" import "../../Constants" // Open Enable Coin Modal -FloatingBackground { +InnerBackground { Item { anchors.fill: parent From edd79826d8f40409f0881c69da74d4e86ce7daa7 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Tue, 28 Jul 2020 19:41:59 +0200 Subject: [PATCH 036/515] enhancements(orderbook): fixing orderbook behavior Signed-off-by: romanszterg --- src/atomic.dex.qt.orderbook.cpp | 8 +++++--- src/atomic.dex.qt.orderbook.model.cpp | 3 +++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/atomic.dex.qt.orderbook.cpp b/src/atomic.dex.qt.orderbook.cpp index 2cfbb0a5e9..b0df439f61 100644 --- a/src/atomic.dex.qt.orderbook.cpp +++ b/src/atomic.dex.qt.orderbook.cpp @@ -19,7 +19,7 @@ namespace atomic_dex { qt_orderbook_wrapper::qt_orderbook_wrapper(ag::ecs::system_manager& system_manager, QObject* parent) : - QObject(parent), m_system_manager(system_manager), m_asks(new orderbook_model( orderbook_model::kind::asks, this)), + QObject(parent), m_system_manager(system_manager), m_asks(new orderbook_model(orderbook_model::kind::asks, this)), m_bids(new orderbook_model(orderbook_model::kind::bids, this)) { spdlog::trace("{} l{} f[{}]", __FUNCTION__, __LINE__, fs::path(__FILE__).filename().string()); @@ -48,8 +48,10 @@ namespace atomic_dex qt_orderbook_wrapper::refresh_orderbook(t_orderbook_answer answer) { spdlog::trace("refresh orderbook"); - this->m_asks->refresh_orderbook(answer); - this->m_bids->refresh_orderbook(answer); + // this->m_asks->refresh_orderbook(answer); + // this->m_bids->refresh_orderbook(answer); + this->m_asks->reset_orderbook(answer); + this->m_bids->reset_orderbook(answer); } void diff --git a/src/atomic.dex.qt.orderbook.model.cpp b/src/atomic.dex.qt.orderbook.model.cpp index 4769e27705..20961c5d00 100644 --- a/src/atomic.dex.qt.orderbook.model.cpp +++ b/src/atomic.dex.qt.orderbook.model.cpp @@ -169,15 +169,18 @@ namespace atomic_dex { if (this->m_orders_id_registry.find(current_order.uuid) != this->m_orders_id_registry.end()) { + //! Update spdlog::trace("updating order id: {}", current_order.uuid); this->update_order(current_order); } else { + //! Insertion spdlog::trace("inserting id: {}", current_order.uuid); this->initialize_order(current_order); } } + //! Deletion std::unordered_set to_remove; for (auto&& id: this->m_orders_id_registry) { From d986849a1886914fb80eb891dc8f426beb3e06fc Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 28 Jul 2020 20:52:18 +0300 Subject: [PATCH 037/515] feat(gui): smaller forms --- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index 8da56c4e1f..64fe8d403e 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -421,7 +421,7 @@ Item { Item { id: forms - width: 400 + width: 375 anchors.right: parent.right anchors.top: parent.top anchors.bottom: parent.bottom @@ -443,7 +443,6 @@ Item { anchors.left: parent.left anchors.right: parent.right anchors.top: form_base.bottom - anchors.bottom: parent.bottom anchors.topMargin: layout_margin field.enabled: enabled && !orderIsSelected() From 6039f238ef823893f87775142eb2b32037add07a Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 28 Jul 2020 21:11:34 +0300 Subject: [PATCH 038/515] feat(gui): move error line under forms --- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 42 ++++++++++--------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index 64fe8d403e..53305b4fb7 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -403,7 +403,7 @@ Item { anchors.right: parent.right anchors.top: parent.top anchors.bottom: orderbook.top - anchors.bottomMargin: layout_margin + anchors.bottomMargin: layout_margin * 2 CandleStickChart { anchors.fill: parent @@ -447,6 +447,28 @@ Item { field.enabled: enabled && !orderIsSelected() } + + // Show errors + DefaultText { + anchors.left: parent.left + anchors.right: parent.right + anchors.top: form_rel.bottom + anchors.topMargin: layout_margin * 2 + + color: Style.colorRed + + text_value: API.get().empty_string + (notEnoughBalanceForFees() ? + (qsTr("Not enough balance for the fees. Need at least %1 more", "AMT TICKER").arg(General.formatCrypto("", parseFloat(curr_trade_info.amount_needed), form_base.getTicker()))) : + (form_base.hasEthFees() && !form_base.hasEnoughEthForFees()) ? (qsTr("Not enough ETH for the transaction fee")) : + (form_base.fieldsAreFilled() && !form_base.higherThanMinTradeAmount()) ? (qsTr("Sell amount is lower than minimum trade amount") + " : " + General.getMinTradeAmount()) : + (form_rel.fieldsAreFilled() && !form_rel.higherThanMinTradeAmount()) ? (qsTr("Receive amount is lower than minimum trade amount") + " : " + General.getMinTradeAmount()) : "" + + ) + visible: form_base.fieldsAreFilled() && (notEnoughBalanceForFees() || + (form_base.hasEthFees() && !form_base.hasEnoughEthForFees()) || + !form_base.higherThanMinTradeAmount() || + (form_rel.fieldsAreFilled() && !form_rel.higherThanMinTradeAmount())) + } } } @@ -455,24 +477,6 @@ Item { Layout.alignment: Qt.AlignBottom | Qt.AlignHCenter } - // Show errors - DefaultText { - Layout.alignment: Qt.AlignBottom | Qt.AlignHCenter - color: Style.colorRed - - text_value: API.get().empty_string + (notEnoughBalanceForFees() ? - (qsTr("Not enough balance for the fees. Need at least %1 more", "AMT TICKER").arg(General.formatCrypto("", parseFloat(curr_trade_info.amount_needed), form_base.getTicker()))) : - (form_base.hasEthFees() && !form_base.hasEnoughEthForFees()) ? (qsTr("Not enough ETH for the transaction fee")) : - (form_base.fieldsAreFilled() && !form_base.higherThanMinTradeAmount()) ? (qsTr("Sell amount is lower than minimum trade amount") + " : " + General.getMinTradeAmount()) : - (form_rel.fieldsAreFilled() && !form_rel.higherThanMinTradeAmount()) ? (qsTr("Receive amount is lower than minimum trade amount") + " : " + General.getMinTradeAmount()) : "" - - ) - visible: form_base.fieldsAreFilled() && (notEnoughBalanceForFees() || - (form_base.hasEthFees() && !form_base.hasEnoughEthForFees()) || - !form_base.higherThanMinTradeAmount() || - (form_rel.fieldsAreFilled() && !form_rel.higherThanMinTradeAmount())) - } - ConfirmTradeModal { id: confirm_trade_modal } From bbe0508db5ecd7279f39ab1adebd7d2ae72ae8fb Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 28 Jul 2020 21:15:06 +0300 Subject: [PATCH 039/515] feat(gui): center dex tabs header --- atomic_qt_design/qml/Exchange/Exchange.qml | 3 +-- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Exchange.qml b/atomic_qt_design/qml/Exchange/Exchange.qml index 3265755ec5..90cad0762f 100644 --- a/atomic_qt_design/qml/Exchange/Exchange.qml +++ b/atomic_qt_design/qml/Exchange/Exchange.qml @@ -85,8 +85,7 @@ Item { height: 62 RowLayout { - anchors.left: parent.left - anchors.leftMargin: 20 + anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter spacing: 30 diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index 53305b4fb7..ab91553b9b 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -386,7 +386,6 @@ Item { Item { Layout.fillWidth: true Layout.fillHeight: true - Layout.bottomMargin: layout_margin Item { id: left_section @@ -474,7 +473,7 @@ Item { // Price PriceLine { - Layout.alignment: Qt.AlignBottom | Qt.AlignHCenter + Layout.alignment: Qt.AlignHCenter } ConfirmTradeModal { From 98f6dd310590f511d5d5e75310a82ed4ceae1eaf Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 28 Jul 2020 21:23:21 +0300 Subject: [PATCH 040/515] feat(gui): fix trade button enabled when not enough balance for fees --- atomic_qt_design/qml/Exchange/Trade/OrderForm.qml | 2 +- atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index 82d2e6bf4d..7e0ae3d6e6 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -466,7 +466,7 @@ FloatingBackground { width: 170 text: API.get().empty_string + (qsTr("Trade")) - enabled: valid_trade_info && form_base.isValid() && form_rel.isValid() + enabled: notEnoughBalanceForFees() && form_base.isValid() && form_rel.isValid() onClicked: confirm_trade_modal.open() } } diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml index 7f7be072f9..ff5590b219 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml @@ -60,8 +60,8 @@ ColumnLayout { id: total_header anchors.left: is_asks ? parent.left : undefined anchors.right: is_asks ? undefined : parent.right - anchors.leftMargin: is_asks ? parent.width * 0.7 : undefined - anchors.rightMargin: is_asks ? undefined : parent.width * 0.7 + anchors.leftMargin: is_asks ? parent.width * 0.6 : undefined + anchors.rightMargin: is_asks ? undefined : parent.width * 0.6 font.pixelSize: price_header.font.pixelSize From 90a64823977eb2f31f236eb4e49a848bff45a334 Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 28 Jul 2020 21:24:09 +0300 Subject: [PATCH 041/515] feat(gui): fix typo --- atomic_qt_design/qml/Exchange/Trade/OrderForm.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index 7e0ae3d6e6..ae9ad1b68c 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -466,7 +466,7 @@ FloatingBackground { width: 170 text: API.get().empty_string + (qsTr("Trade")) - enabled: notEnoughBalanceForFees() && form_base.isValid() && form_rel.isValid() + enabled: valid_trade_info && !notEnoughBalanceForFees() && form_base.isValid() && form_rel.isValid() onClicked: confirm_trade_modal.open() } } From c342c7109395045c667d051cdb33d2522e14ea4d Mon Sep 17 00:00:00 2001 From: romanszterg Date: Tue, 28 Jul 2020 20:30:21 +0200 Subject: [PATCH 042/515] enhancements(orderbook): scroll finished Signed-off-by: romanszterg --- src/atomic.dex.qt.orderbook.cpp | 6 ++---- src/atomic.dex.qt.orderbook.hpp | 2 +- src/atomic.dex.qt.orderbook.model.cpp | 14 ++++++++------ 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/atomic.dex.qt.orderbook.cpp b/src/atomic.dex.qt.orderbook.cpp index b0df439f61..443c112d4e 100644 --- a/src/atomic.dex.qt.orderbook.cpp +++ b/src/atomic.dex.qt.orderbook.cpp @@ -48,10 +48,8 @@ namespace atomic_dex qt_orderbook_wrapper::refresh_orderbook(t_orderbook_answer answer) { spdlog::trace("refresh orderbook"); - // this->m_asks->refresh_orderbook(answer); - // this->m_bids->refresh_orderbook(answer); - this->m_asks->reset_orderbook(answer); - this->m_bids->reset_orderbook(answer); + this->m_asks->refresh_orderbook(answer); + this->m_bids->refresh_orderbook(answer); } void diff --git a/src/atomic.dex.qt.orderbook.hpp b/src/atomic.dex.qt.orderbook.hpp index 2166424237..0426c0fe0b 100644 --- a/src/atomic.dex.qt.orderbook.hpp +++ b/src/atomic.dex.qt.orderbook.hpp @@ -39,7 +39,7 @@ namespace atomic_dex public: void refresh_orderbook(t_orderbook_answer answer); void reset_orderbook(t_orderbook_answer answer); - void clear_orderbook();; + void clear_orderbook(); [[nodiscard]] orderbook_model* get_asks() const noexcept; [[nodiscard]] orderbook_model* get_bids() const noexcept; diff --git a/src/atomic.dex.qt.orderbook.model.cpp b/src/atomic.dex.qt.orderbook.model.cpp index 20961c5d00..71bf0573e5 100644 --- a/src/atomic.dex.qt.orderbook.model.cpp +++ b/src/atomic.dex.qt.orderbook.model.cpp @@ -116,6 +116,7 @@ namespace atomic_dex this->beginResetModel(); m_model_data = orderbook; std::vector<::mm2::api::order_contents>& model_data = this->m_current_orderbook_kind == kind::asks ? this->m_model_data.asks : this->m_model_data.bids; + spdlog::trace("reset with orderbook of size: {}", model_data.size()); m_orders_id_registry.clear(); for (auto&& order: model_data) { @@ -124,9 +125,9 @@ namespace atomic_dex this->m_orders_id_registry.emplace(order.uuid); } } - this->endResetModel(); emit lengthChanged(); + assert(model_data.size() == m_orders_id_registry.size()); } int @@ -140,11 +141,13 @@ namespace atomic_dex orderbook_model::initialize_order(const ::mm2::api::order_contents& order) noexcept { std::vector<::mm2::api::order_contents>& model_data = this->m_current_orderbook_kind == kind::asks ? this->m_model_data.asks : this->m_model_data.bids; + assert(model_data.size() == m_orders_id_registry.size()); beginInsertRows(QModelIndex(), model_data.size(), model_data.size()); model_data.push_back(order); this->m_orders_id_registry.emplace(order.uuid); endInsertRows(); emit lengthChanged(); + assert(model_data.size() == m_orders_id_registry.size()); } void @@ -163,7 +166,6 @@ namespace atomic_dex void orderbook_model::refresh_orderbook(const t_orderbook_answer& orderbook) noexcept { - m_model_data = orderbook; auto refresh_functor = [this](const std::vector<::mm2::api::order_contents>& contents) { for (auto&& current_order: contents) { @@ -176,11 +178,11 @@ namespace atomic_dex else { //! Insertion - spdlog::trace("inserting id: {}", current_order.uuid); + spdlog::trace("id {} not present in the registry, inserting", current_order.uuid); this->initialize_order(current_order); } } - //! Deletion + std::unordered_set to_remove; for (auto&& id: this->m_orders_id_registry) { @@ -202,10 +204,10 @@ namespace atomic_dex switch (this->m_current_orderbook_kind) { case kind::asks: - refresh_functor(this->m_model_data.asks); + refresh_functor(orderbook.asks); break; case kind::bids: - refresh_functor(this->m_model_data.bids); + refresh_functor(orderbook.bids); break; } } From f2882dcfe4ea90312d0175e9fe89a7554718d102 Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 28 Jul 2020 21:30:58 +0300 Subject: [PATCH 043/515] feat(gui): adjust column margins --- .../qml/Exchange/Trade/OrderbookSection.qml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml index ff5590b219..f922884ac5 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml @@ -34,8 +34,8 @@ ColumnLayout { anchors.left: is_asks ? parent.left : undefined anchors.right: is_asks ? undefined : parent.right - anchors.leftMargin: is_asks ? parent.width * 0.02 : undefined - anchors.rightMargin: is_asks ? undefined : parent.width * 0.02 + anchors.leftMargin: is_asks ? parent.width * 0.03 : undefined + anchors.rightMargin: is_asks ? undefined : parent.width * 0.03 anchors.verticalCenter: parent.verticalCenter } @@ -45,8 +45,8 @@ ColumnLayout { id: quantity_header anchors.left: is_asks ? parent.left : undefined anchors.right: is_asks ? undefined : parent.right - anchors.leftMargin: is_asks ? parent.width * 0.3 : undefined - anchors.rightMargin: is_asks ? undefined : parent.width * 0.3 + anchors.leftMargin: is_asks ? parent.width * 0.32 : undefined + anchors.rightMargin: is_asks ? undefined : parent.width * 0.32 font.pixelSize: price_header.font.pixelSize @@ -60,8 +60,8 @@ ColumnLayout { id: total_header anchors.left: is_asks ? parent.left : undefined anchors.right: is_asks ? undefined : parent.right - anchors.leftMargin: is_asks ? parent.width * 0.6 : undefined - anchors.rightMargin: is_asks ? undefined : parent.width * 0.6 + anchors.leftMargin: is_asks ? parent.width * 0.65 : undefined + anchors.rightMargin: is_asks ? undefined : parent.width * 0.65 font.pixelSize: price_header.font.pixelSize From 22b5a20cf4cda016004a7803c9aa236426cf0413 Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 28 Jul 2020 21:36:49 +0300 Subject: [PATCH 044/515] feat(gui): smaller lines --- atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml | 2 +- atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml b/atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml index 66df3ed1e2..728dc0530c 100644 --- a/atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml +++ b/atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml @@ -636,7 +636,7 @@ Item { DefaultText { visible: !pair_supported - text_value: API.get().empty_string + (qsTr("We don't have chart data for this pair yet")) + text_value: API.get().empty_string + (qsTr("There is no chart data for this pair yet")) anchors.centerIn: parent } } diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml index f922884ac5..96f25f5e02 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml @@ -20,7 +20,7 @@ ColumnLayout { Item { Layout.fillWidth: true - height: 50 + height: 40 // Price DefaultText { @@ -91,7 +91,7 @@ ColumnLayout { color: mouse_area.containsMouse ? Style.colorTheme4 : "transparent" width: root.width - height: 50 + height: 20 MouseArea { id: mouse_area From 18901a045aee7c8e7ba4a98bd47b6d5578feb30d Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 28 Jul 2020 21:44:23 +0300 Subject: [PATCH 045/515] feat(gui): remove orderbook modal --- atomic_qt_design/qml/Exchange/OrderModal.qml | 187 ------------------ .../qml/Exchange/Trade/OrderForm.qml | 4 - .../qml/Exchange/Trade/OrderReceiveModal.qml | 3 - atomic_qt_design/qml/Exchange/Trade/Trade.qml | 20 -- 4 files changed, 214 deletions(-) delete mode 100644 atomic_qt_design/qml/Exchange/OrderModal.qml diff --git a/atomic_qt_design/qml/Exchange/OrderModal.qml b/atomic_qt_design/qml/Exchange/OrderModal.qml deleted file mode 100644 index 9c44d4d80e..0000000000 --- a/atomic_qt_design/qml/Exchange/OrderModal.qml +++ /dev/null @@ -1,187 +0,0 @@ -import QtQuick 2.12 -import QtQuick.Layouts 1.12 -import QtQuick.Controls 2.12 - -import "../Components" -import "../Constants" - -// Open Enable Coin Modal -DefaultModal { - id: root - - width: 900 - property var details - - onDetailsChanged: { - if(!details) root.close() - } - - // Inside modal - ColumnLayout { - width: parent.width - height: parent.height - anchors.horizontalCenter: parent.horizontalCenter - - ModalHeader { - title: API.get().empty_string + (!details ? "" : - details.is_swap ? qsTr("Swap Details") : qsTr("Order Details")) - } - - // Complete image - DefaultImage { - visible: !details ? false : - details.is_swap && details.order_status === "successful" - Layout.alignment: Qt.AlignHCenter - source: General.image_path + "exchange-trade-complete.svg" - } - - // Loading symbol - DefaultBusyIndicator { - visible: !details ? false : - details.is_swap && - details.order_status !== "successful" && - details.order_status !== "failed" - Layout.alignment: Qt.AlignHCenter - } - - // Status Text - DefaultText { - Layout.alignment: Qt.AlignHCenter - Layout.topMargin: 20 - font.pixelSize: Style.textSize3 - visible: !details ? false : - details.is_swap || !details.is_maker - color: !details ? "white" : - visible ? getStatusColor(details.order_status) : '' - text_value: API.get().empty_string + (!details ? "" : - visible ? getStatusTextWithPrefix(details.order_status) : '') - } - - OrderContent { - Layout.topMargin: 25 - Layout.fillWidth: true - Layout.leftMargin: 20 - Layout.rightMargin: Layout.leftMargin - height: 120 - Layout.alignment: Qt.AlignHCenter - details: root.details - in_modal: true - } - - HorizontalLine { - Layout.fillWidth: true - Layout.bottomMargin: 20 - color: Style.colorWhite8 - } - - // Maker/Taker - DefaultText { - text_value: API.get().empty_string + (!details ? "" : - details.is_maker ? qsTr("Maker Order"): qsTr("Taker Order")) - color: Style.colorThemeDarkLight - Layout.alignment: Qt.AlignRight - } - - // Refund state - TextFieldWithTitle { - Layout.topMargin: -20 - - title: API.get().empty_string + (qsTr("Refund State")) - field.text: !details ? "" : - details.order_status === "refunding" ? qsTr("Your swap failed but the auto-refund process for your payment started already. Please wait and keep application opened until you receive your payment back") : "" - field.readOnly: true - - visible: field.text !== '' - } - - // Date - TextWithTitle { - title: API.get().empty_string + (qsTr("Date")) - text: API.get().empty_string + (!details ? "" : - details.date) - visible: text !== '' - } - - // ID - TextWithTitle { - title: API.get().empty_string + (qsTr("ID")) - text: API.get().empty_string + (!details ? "" : - details.order_id) - visible: text !== '' - privacy: true - } - - // Payment ID - TextWithTitle { - title: API.get().empty_string + (!details ? "" : - details.is_maker ? qsTr("Maker Payment Sent ID") : qsTr("Maker Payment Spent ID")) - text: API.get().empty_string + (!details ? "" : - details.maker_payment_id) - visible: text !== '' - privacy: true - } - - // Payment ID - TextWithTitle { - title: API.get().empty_string + (!details ? "" : - details.is_maker ? qsTr("Taker Payment Spent ID") : qsTr("Taker Payment Sent ID")) - text: API.get().empty_string + (!details ? "" : - details.taker_payment_id) - visible: text !== '' - privacy: true - } - - // Error ID - TextWithTitle { - title: API.get().empty_string + (qsTr("Error ID")) - text: API.get().empty_string + (!details ? "" : - details.order_error_state) - visible: text !== '' - } - - // Error Details - TextFieldWithTitle { - title: API.get().empty_string + (qsTr("Error Log")) - field.text: API.get().empty_string + (!details ? "" : - details.order_error_message) - field.readOnly: true - copyable: true - - visible: field.text !== '' - } - - // Buttons - RowLayout { - DefaultButton { - text: API.get().empty_string + (qsTr("Close")) - Layout.fillWidth: true - onClicked: root.close() - } - - // Cancel button - DangerButton { - visible: !details ? false : - details.cancellable - Layout.fillWidth: true - text: API.get().empty_string + (qsTr("Cancel Order")) - onClicked: { if(details) onCancelOrder(details.order_id) } - } - - PrimaryButton { - text: API.get().empty_string + (qsTr("View at Explorer")) - Layout.fillWidth: true - visible: !details ? false : - details.maker_payment_id !== '' || details.taker_payment_id !== '' - onClicked: { - if(!details) return - - const maker_id = details.maker_payment_id - const taker_id = details.taker_payment_id - - if(maker_id !== '') General.viewTxAtExplorer(details.is_maker ? details.base_coin : details.rel_coin, maker_id, true) - if(taker_id !== '') General.viewTxAtExplorer(details.is_maker ? details.rel_coin : details.base_coin, taker_id, true) - } - } - } - } -} diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index ae9ad1b68c..f12aa0dddd 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -251,10 +251,6 @@ FloatingBackground { OrderReceiveModal { id: order_receive_modal } - - OrderbookModal { - id: orderbook_modal - } } } diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderReceiveModal.qml b/atomic_qt_design/qml/Exchange/Trade/OrderReceiveModal.qml index 0b803039de..60f05bf784 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderReceiveModal.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderReceiveModal.qml @@ -62,9 +62,6 @@ DefaultModal { if(getOrderCount(model.modelData.ticker) === 0) { } - else { - orderbook_modal.open() - } } } diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index ab91553b9b..2676ab8a6b 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -224,14 +224,6 @@ Item { } } - function getCurrentOrderbook() { - if(orderbook_model === undefined) return [] - - const cb = orderbook_model[getTicker()] - - return cb === undefined ? [] : cb - } - function moveToBeginning(coins, ticker) { const idx = coins.map(c => c.ticker).indexOf(ticker) if(idx === -1) return @@ -338,18 +330,6 @@ Item { return parseFloat(valid_trade_info ? info.input_final_value : amount) } - function getReceiveAmount(price, volume) { - let new_rel = newRelVolume(price) - - // If new rel volume is higher than the order max volume - const max_volume = parseFloat(volume) - if(new_rel > max_volume) { - new_rel = max_volume - } - - return General.formatDouble(new_rel) - } - // No coins warning ColumnLayout { anchors.centerIn: parent From 973bcb811d01261388c8d7a4202fb61765f73756 Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 28 Jul 2020 21:48:37 +0300 Subject: [PATCH 046/515] feat(gui): remove receive ticker modal --- .../qml/Exchange/Trade/OrderForm.qml | 12 -- .../qml/Exchange/Trade/OrderReceiveModal.qml | 104 ------------------ 2 files changed, 116 deletions(-) delete mode 100644 atomic_qt_design/qml/Exchange/Trade/OrderReceiveModal.qml diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index f12aa0dddd..c36c1080cf 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -239,18 +239,6 @@ FloatingBackground { setPair(my_side) } } - - MouseArea { - visible: !my_side - anchors.fill: parent - onClicked: { - order_receive_modal.open() - } - } - - OrderReceiveModal { - id: order_receive_modal - } } } diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderReceiveModal.qml b/atomic_qt_design/qml/Exchange/Trade/OrderReceiveModal.qml deleted file mode 100644 index 60f05bf784..0000000000 --- a/atomic_qt_design/qml/Exchange/Trade/OrderReceiveModal.qml +++ /dev/null @@ -1,104 +0,0 @@ -import QtQuick 2.12 -import QtQuick.Layouts 1.12 -import QtQuick.Controls 2.12 - -import "../../Components" -import "../../Constants" - -// Open Enable Coin Modal -DefaultModal { - id: root_modal - - function getOrderCount(ticker) { - if(orderbook_model === undefined) return 0 - - const book = orderbook_model[ticker] - if(book === undefined) return 0 - - return book.length - } - - width: 500 - - // Inside modal - ColumnLayout { - id: modal_layout - - width: parent.width - - ModalHeader { - title: API.get().empty_string + (qsTr("Receive")) - } - - // Search input - DefaultTextField { - id: input_coin_filter - - Layout.fillWidth: true - placeholderText: API.get().empty_string + (qsTr("Search")) - selectByMouse: true - } - - // List - DefaultListView { - id: list - implicitHeight: 600 - - model: General.filterCoins(getFilteredCoins().sort((a, b) => getOrderCount(b.ticker) - getOrderCount(a.ticker)), input_coin_filter.text) - - delegate: Rectangle { - color: mouse_area.containsMouse ? Style.colorTheme4 : "transparent" - - width: modal_layout.width - height: 50 - - MouseArea { - id: mouse_area - anchors.fill: parent - hoverEnabled: true - onClicked: { - setTicker(model.modelData.ticker) - root_modal.close() - if(getOrderCount(model.modelData.ticker) === 0) { - - } - } - } - - // Icon - DefaultImage { - id: icon - anchors.left: parent.left - anchors.leftMargin: 20 - - source: General.coinIcon(model.modelData.ticker) - fillMode: Image.PreserveAspectFit - width: Style.textSize2 - anchors.verticalCenter: parent.verticalCenter - } - - // Name - DefaultText { - anchors.left: icon.right - anchors.leftMargin: Style.iconTextMargin - - text_value: API.get().empty_string + (model.modelData.name + " (" + model.modelData.ticker + ")" + " - " + - (getOrderCount(model.modelData.ticker) === 0 ? qsTr("Click to create an order") : - qsTr("Click to see %n order(s)", "", getOrderCount(model.modelData.ticker)))) - anchors.verticalCenter: parent.verticalCenter - - color: getOrderCount(model.modelData.ticker) === 0 ? Style.colorWhite1 : Style.colorTheme0 - } - } - } - - // Buttons - RowLayout { - DefaultButton { - text: API.get().empty_string + (qsTr("Close")) - Layout.fillWidth: true - onClicked: root_modal.close() - } - } - } -} From 6b872090575d01af8d20f23b70efafd8584f21ee Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 28 Jul 2020 21:54:29 +0300 Subject: [PATCH 047/515] feat(gui): clean old orderbook code --- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 25 ++----------------- 1 file changed, 2 insertions(+), 23 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index 2676ab8a6b..8bf2638f1e 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -22,7 +22,6 @@ Item { function fullReset() { reset(true) - orderbook_timer.running = false } function reset(reset_result=true, is_base) { @@ -33,16 +32,6 @@ Item { resetTradeInfo() } - Timer { - id: orderbook_timer - repeat: true - interval: 5000 - onTriggered: { - if(inCurrentPage()) updateOrderbook() - } - } - - // Price property string cex_price function updateCexPrice(base, rel) { @@ -169,21 +158,11 @@ Item { // Orderbook - property var orderbook_model - function fillTickersIfEmpty() { form_base.fillIfEmpty() form_rel.fillIfEmpty() } - function updateOrderbook() { - fillTickersIfEmpty() - - orderbook_model = API.mockAPI.get_orderbook(getTicker(true)) - orderbook_timer.running = true - updateTradeInfo() - } - function updateTradeInfo(force=false) { const base = getTicker(true) const rel = getTicker(false) @@ -205,7 +184,7 @@ Item { } function onOpened() { - updateOrderbook() + fillTickersIfEmpty() reset(true) updateForms() setPair(true) @@ -286,7 +265,7 @@ Item { console.log("Setting current orderbook with params: ", new_base, rel) API.get().set_current_orderbook(new_base, rel) reset(true, is_base) - updateOrderbook() + updateTradeInfo() updateCexPrice(new_base, rel) exchange.onTradeTickerChanged(new_base) } From 7e130eea6f2cd6dd840ed6e3acb9be7dff2350b8 Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 28 Jul 2020 22:03:37 +0300 Subject: [PATCH 048/515] feat(gui): start adding unlock price button --- atomic_qt_design/qml/Exchange/OrderModal.qml | 187 ++++++++++++++++++ .../qml/Exchange/Trade/OrderForm.qml | 26 ++- .../qml/Exchange/Trade/OrderbookModal.qml | 165 ---------------- qml.qrc | 2 - 4 files changed, 205 insertions(+), 175 deletions(-) create mode 100644 atomic_qt_design/qml/Exchange/OrderModal.qml delete mode 100644 atomic_qt_design/qml/Exchange/Trade/OrderbookModal.qml diff --git a/atomic_qt_design/qml/Exchange/OrderModal.qml b/atomic_qt_design/qml/Exchange/OrderModal.qml new file mode 100644 index 0000000000..9c44d4d80e --- /dev/null +++ b/atomic_qt_design/qml/Exchange/OrderModal.qml @@ -0,0 +1,187 @@ +import QtQuick 2.12 +import QtQuick.Layouts 1.12 +import QtQuick.Controls 2.12 + +import "../Components" +import "../Constants" + +// Open Enable Coin Modal +DefaultModal { + id: root + + width: 900 + property var details + + onDetailsChanged: { + if(!details) root.close() + } + + // Inside modal + ColumnLayout { + width: parent.width + height: parent.height + anchors.horizontalCenter: parent.horizontalCenter + + ModalHeader { + title: API.get().empty_string + (!details ? "" : + details.is_swap ? qsTr("Swap Details") : qsTr("Order Details")) + } + + // Complete image + DefaultImage { + visible: !details ? false : + details.is_swap && details.order_status === "successful" + Layout.alignment: Qt.AlignHCenter + source: General.image_path + "exchange-trade-complete.svg" + } + + // Loading symbol + DefaultBusyIndicator { + visible: !details ? false : + details.is_swap && + details.order_status !== "successful" && + details.order_status !== "failed" + Layout.alignment: Qt.AlignHCenter + } + + // Status Text + DefaultText { + Layout.alignment: Qt.AlignHCenter + Layout.topMargin: 20 + font.pixelSize: Style.textSize3 + visible: !details ? false : + details.is_swap || !details.is_maker + color: !details ? "white" : + visible ? getStatusColor(details.order_status) : '' + text_value: API.get().empty_string + (!details ? "" : + visible ? getStatusTextWithPrefix(details.order_status) : '') + } + + OrderContent { + Layout.topMargin: 25 + Layout.fillWidth: true + Layout.leftMargin: 20 + Layout.rightMargin: Layout.leftMargin + height: 120 + Layout.alignment: Qt.AlignHCenter + details: root.details + in_modal: true + } + + HorizontalLine { + Layout.fillWidth: true + Layout.bottomMargin: 20 + color: Style.colorWhite8 + } + + // Maker/Taker + DefaultText { + text_value: API.get().empty_string + (!details ? "" : + details.is_maker ? qsTr("Maker Order"): qsTr("Taker Order")) + color: Style.colorThemeDarkLight + Layout.alignment: Qt.AlignRight + } + + // Refund state + TextFieldWithTitle { + Layout.topMargin: -20 + + title: API.get().empty_string + (qsTr("Refund State")) + field.text: !details ? "" : + details.order_status === "refunding" ? qsTr("Your swap failed but the auto-refund process for your payment started already. Please wait and keep application opened until you receive your payment back") : "" + field.readOnly: true + + visible: field.text !== '' + } + + // Date + TextWithTitle { + title: API.get().empty_string + (qsTr("Date")) + text: API.get().empty_string + (!details ? "" : + details.date) + visible: text !== '' + } + + // ID + TextWithTitle { + title: API.get().empty_string + (qsTr("ID")) + text: API.get().empty_string + (!details ? "" : + details.order_id) + visible: text !== '' + privacy: true + } + + // Payment ID + TextWithTitle { + title: API.get().empty_string + (!details ? "" : + details.is_maker ? qsTr("Maker Payment Sent ID") : qsTr("Maker Payment Spent ID")) + text: API.get().empty_string + (!details ? "" : + details.maker_payment_id) + visible: text !== '' + privacy: true + } + + // Payment ID + TextWithTitle { + title: API.get().empty_string + (!details ? "" : + details.is_maker ? qsTr("Taker Payment Spent ID") : qsTr("Taker Payment Sent ID")) + text: API.get().empty_string + (!details ? "" : + details.taker_payment_id) + visible: text !== '' + privacy: true + } + + // Error ID + TextWithTitle { + title: API.get().empty_string + (qsTr("Error ID")) + text: API.get().empty_string + (!details ? "" : + details.order_error_state) + visible: text !== '' + } + + // Error Details + TextFieldWithTitle { + title: API.get().empty_string + (qsTr("Error Log")) + field.text: API.get().empty_string + (!details ? "" : + details.order_error_message) + field.readOnly: true + copyable: true + + visible: field.text !== '' + } + + // Buttons + RowLayout { + DefaultButton { + text: API.get().empty_string + (qsTr("Close")) + Layout.fillWidth: true + onClicked: root.close() + } + + // Cancel button + DangerButton { + visible: !details ? false : + details.cancellable + Layout.fillWidth: true + text: API.get().empty_string + (qsTr("Cancel Order")) + onClicked: { if(details) onCancelOrder(details.order_id) } + } + + PrimaryButton { + text: API.get().empty_string + (qsTr("View at Explorer")) + Layout.fillWidth: true + visible: !details ? false : + details.maker_payment_id !== '' || details.taker_payment_id !== '' + onClicked: { + if(!details) return + + const maker_id = details.maker_payment_id + const taker_id = details.taker_payment_id + + if(maker_id !== '') General.viewTxAtExplorer(details.is_maker ? details.base_coin : details.rel_coin, maker_id, true) + if(taker_id !== '') General.viewTxAtExplorer(details.is_maker ? details.rel_coin : details.base_coin, taker_id, true) + } + } + } + } +} diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index c36c1080cf..0785ebdc60 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -440,18 +440,28 @@ FloatingBackground { } - // Trade button - DefaultButton { - visible: !my_side - + RowLayout { Layout.alignment: Qt.AlignRight | Qt.AlignBottom Layout.rightMargin: top_line.Layout.rightMargin Layout.bottomMargin: top_line.Layout.rightMargin - width: 170 - text: API.get().empty_string + (qsTr("Trade")) - enabled: valid_trade_info && !notEnoughBalanceForFees() && form_base.isValid() && form_rel.isValid() - onClicked: confirm_trade_modal.open() + DefaultButton { + visible: !my_side + + text: API.get().empty_string + (qsTr("Unlock Price")) + enabled: orderIsSelected() + onClicked: resetPreferredPrice() + } + + // Trade button + DefaultButton { + visible: !my_side + width: 170 + + text: API.get().empty_string + (qsTr("Trade")) + enabled: valid_trade_info && !notEnoughBalanceForFees() && form_base.isValid() && form_rel.isValid() + onClicked: confirm_trade_modal.open() + } } } } diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderbookModal.qml b/atomic_qt_design/qml/Exchange/Trade/OrderbookModal.qml deleted file mode 100644 index 4071521d90..0000000000 --- a/atomic_qt_design/qml/Exchange/Trade/OrderbookModal.qml +++ /dev/null @@ -1,165 +0,0 @@ -import QtQuick 2.12 -import QtQuick.Layouts 1.12 -import QtQuick.Controls 2.12 - -import "../../Components" -import "../../Constants" - -// Open Enable Coin Modal -DefaultModal { - id: root - - function createNewOrder() { - prepareCreateMyOwnOrder() - root.close() - } - - function chooseOrder(order) { - // Choose this order - selectOrder(order) - root.close() - } - - width: 900 - height: 600 - - // Inside modal - ColumnLayout { - id: modal_layout - - width: parent.width - height: parent.height - - ModalHeader { - title: API.get().empty_string + (qsTr("Orderbook")) - bottomMargin: 0 - } - - // List header - Item { - Layout.alignment: Qt.AlignTop - - Layout.fillWidth: true - - height: 50 - - // Price - DefaultText { - id: price_header - anchors.right: parent.right - anchors.rightMargin: parent.width * 0.77 - - text_value: API.get().empty_string + (qsTr("Price")) - color: Style.colorWhite1 - anchors.verticalCenter: parent.verticalCenter - } - - // Volume - DefaultText { - id: volume_header - anchors.right: parent.right - anchors.rightMargin: parent.width * 0.44 - - text_value: API.get().empty_string + (qsTr("Volume")) - color: Style.colorWhite1 - anchors.verticalCenter: parent.verticalCenter - } - - // Receive amount - DefaultText { - id: receive_header - anchors.right: parent.right - anchors.rightMargin: parent.width * 0.11 - - text_value: API.get().empty_string + (qsTr("Receive")) - color: Style.colorWhite1 - anchors.verticalCenter: parent.verticalCenter - } - - // Line - HorizontalLine { - width: parent.width - color: Style.colorWhite5 - anchors.bottom: parent.bottom - } - } - - // List - DefaultListView { - id: list - Layout.alignment: Qt.AlignTop - Layout.fillWidth: true - Layout.fillHeight: true - - model: getCurrentOrderbook().sort((a, b) => parseFloat(b.price) - parseFloat(a.price)) - - delegate: Rectangle { - color: mouse_area.containsMouse ? Style.colorTheme4 : "transparent" - - width: modal_layout.width - height: 50 - - MouseArea { - id: mouse_area - anchors.fill: parent - hoverEnabled: true - onClicked: chooseOrder(model.modelData) - } - - // Price - DefaultText { - anchors.right: parent.right - anchors.rightMargin: price_header.anchors.rightMargin - - text_value: API.get().empty_string + (General.formatDouble(model.modelData.price)) - color: Style.colorWhite4 - anchors.verticalCenter: parent.verticalCenter - } - - // Volume - DefaultText { - anchors.right: parent.right - anchors.rightMargin: volume_header.anchors.rightMargin - - text_value: API.get().empty_string + (model.modelData.volume) - color: Style.colorWhite4 - anchors.verticalCenter: parent.verticalCenter - } - - // Receive amount - DefaultText { - anchors.right: parent.right - anchors.rightMargin: receive_header.anchors.rightMargin - - text_value: API.get().empty_string + (getReceiveAmount(model.modelData.price, model.modelData.volume) + " " + getTicker()) - color: Style.colorWhite4 - anchors.verticalCenter: parent.verticalCenter - } - - // Line - HorizontalLine { - visible: index !== getCurrentOrderbook().length - 1 - width: parent.width - color: Style.colorWhite9 - anchors.bottom: parent.bottom - } - } - } - - // Buttons - RowLayout { - Layout.alignment: Qt.AlignBottom - DefaultButton { - text: API.get().empty_string + (qsTr("Close")) - Layout.fillWidth: true - onClicked: root.close() - } - - PrimaryButton { - text: API.get().empty_string + (qsTr("Create your own order")) - Layout.fillWidth: true - onClicked: createNewOrder() - } - } - } -} diff --git a/qml.qrc b/qml.qrc index b4c5354d76..1dbb7230de 100644 --- a/qml.qrc +++ b/qml.qrc @@ -107,9 +107,7 @@ atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml atomic_qt_design/qml/Exchange/Trade/PriceLine.qml atomic_qt_design/qml/Exchange/Trade/OrderForm.qml - atomic_qt_design/qml/Exchange/Trade/OrderReceiveModal.qml atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml - atomic_qt_design/qml/Exchange/Trade/OrderbookModal.qml atomic_qt_design/qml/Exchange/Trade/Orderbook.qml atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml atomic_qt_design/qml/Exchange/Orders/Orders.qml From 0daa970532f1a971cc84c9d36a45feedd993106e Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 28 Jul 2020 22:14:07 +0300 Subject: [PATCH 049/515] feat(gui): layout adjustments --- atomic_qt_design/qml/Exchange/Trade/OrderForm.qml | 8 ++++---- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 5 +---- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index 0785ebdc60..30455998bf 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -379,7 +379,7 @@ FloatingBackground { Layout.fillWidth: true Layout.leftMargin: top_line.Layout.leftMargin Layout.rightMargin: top_line.Layout.rightMargin - Layout.bottomMargin: top_line.Layout.rightMargin + Layout.bottomMargin: layout_margin content: RowLayout { width: bg.width @@ -442,14 +442,14 @@ FloatingBackground { RowLayout { Layout.alignment: Qt.AlignRight | Qt.AlignBottom + Layout.topMargin: 5 Layout.rightMargin: top_line.Layout.rightMargin - Layout.bottomMargin: top_line.Layout.rightMargin + Layout.bottomMargin: layout_margin DefaultButton { - visible: !my_side + visible: orderIsSelected() text: API.get().empty_string + (qsTr("Unlock Price")) - enabled: orderIsSelected() onClicked: resetPreferredPrice() } diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index 8bf2638f1e..a2ce4c4e17 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -50,10 +50,6 @@ Item { preffered_order = General.clone(empty_order) } - function prepareCreateMyOwnOrder() { - resetPreferredPrice() - } - function selectOrder(order) { preffered_order.price = order.price preffered_order.volume = order.volume @@ -413,6 +409,7 @@ Item { anchors.top: form_rel.bottom anchors.topMargin: layout_margin * 2 + font.pixelSize: Style.textSizeSmall4 color: Style.colorRed text_value: API.get().empty_string + (notEnoughBalanceForFees() ? From 7a8a73139dcfa23ae9d7fc41fd446aa3965f200c Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 28 Jul 2020 22:24:06 +0300 Subject: [PATCH 050/515] feat(gui): update trading fees quicker --- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index a2ce4c4e17..aa9e618d8c 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -117,6 +117,7 @@ Item { Timer { id: trade_info_timer repeat: true + running: true interval: 500 onTriggered: { if(inCurrentPage() && !valid_trade_info) { From 406adeabd2e66b14e0d72c3ee90dee0e8c4351ae Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 28 Jul 2020 22:46:22 +0300 Subject: [PATCH 051/515] feat(gui): disable mouse hover on orderbook --- atomic_qt_design/qml/Exchange/OrderModal.qml | 1 - .../qml/Exchange/Trade/ConfirmTradeModal.qml | 1 - atomic_qt_design/qml/Exchange/Trade/Orderbook.qml | 1 - atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml | 9 ++------- atomic_qt_design/qml/Settings/DeleteWalletModal.qml | 1 - atomic_qt_design/qml/Settings/RecoverSeedModal.qml | 1 - atomic_qt_design/qml/Wallet/EnableCoinModal.qml | 1 - atomic_qt_design/qml/Wallet/ReceiveModal.qml | 1 - atomic_qt_design/qml/Wallet/SendModal.qml | 1 - 9 files changed, 2 insertions(+), 15 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/OrderModal.qml b/atomic_qt_design/qml/Exchange/OrderModal.qml index 9c44d4d80e..92a5815bf0 100644 --- a/atomic_qt_design/qml/Exchange/OrderModal.qml +++ b/atomic_qt_design/qml/Exchange/OrderModal.qml @@ -5,7 +5,6 @@ import QtQuick.Controls 2.12 import "../Components" import "../Constants" -// Open Enable Coin Modal DefaultModal { id: root diff --git a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml index 5eaab320c6..c103367b69 100644 --- a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml +++ b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml @@ -6,7 +6,6 @@ import "../../Components" import "../../Constants" import ".." -// Open Enable Coin Modal DefaultModal { id: root diff --git a/atomic_qt_design/qml/Exchange/Trade/Orderbook.qml b/atomic_qt_design/qml/Exchange/Trade/Orderbook.qml index f98b5015ec..d999e2e3b5 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Orderbook.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Orderbook.qml @@ -5,7 +5,6 @@ import QtQuick.Controls 2.12 import "../../Components" import "../../Constants" -// Open Enable Coin Modal InnerBackground { Item { anchors.fill: parent diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml index 96f25f5e02..b425127715 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml @@ -5,16 +5,11 @@ import QtQuick.Controls 2.12 import "../../Components" import "../../Constants" -// Open Enable Coin Modal ColumnLayout { id: root property bool is_asks: false property alias model: list.model - function chooseOrder(order) { - // Choose this order - selectOrder(order) - } // List header Item { @@ -88,7 +83,7 @@ ColumnLayout { Layout.fillHeight: true delegate: Rectangle { - color: mouse_area.containsMouse ? Style.colorTheme4 : "transparent" + color: /*mouse_area.containsMouse ? Style.colorTheme4 : */"transparent" width: root.width height: 20 @@ -97,7 +92,7 @@ ColumnLayout { id: mouse_area anchors.fill: parent hoverEnabled: true - //onClicked: chooseOrder(model.modelData) + //onClicked: selectOrder(model.modelData) } // Price diff --git a/atomic_qt_design/qml/Settings/DeleteWalletModal.qml b/atomic_qt_design/qml/Settings/DeleteWalletModal.qml index c9aebd4e28..77e1026cc2 100644 --- a/atomic_qt_design/qml/Settings/DeleteWalletModal.qml +++ b/atomic_qt_design/qml/Settings/DeleteWalletModal.qml @@ -5,7 +5,6 @@ import QtQuick.Controls 2.12 import "../Components" import "../Constants" -// Open Enable Coin Modal DefaultModal { id: root diff --git a/atomic_qt_design/qml/Settings/RecoverSeedModal.qml b/atomic_qt_design/qml/Settings/RecoverSeedModal.qml index 9ccf69f02e..bf566ed409 100644 --- a/atomic_qt_design/qml/Settings/RecoverSeedModal.qml +++ b/atomic_qt_design/qml/Settings/RecoverSeedModal.qml @@ -5,7 +5,6 @@ import QtQuick.Controls 2.12 import "../Components" import "../Constants" -// Open Enable Coin Modal DefaultModal { id: root diff --git a/atomic_qt_design/qml/Wallet/EnableCoinModal.qml b/atomic_qt_design/qml/Wallet/EnableCoinModal.qml index 7b816f4ac5..3c07984c0f 100644 --- a/atomic_qt_design/qml/Wallet/EnableCoinModal.qml +++ b/atomic_qt_design/qml/Wallet/EnableCoinModal.qml @@ -5,7 +5,6 @@ import QtQuick.Controls 2.12 import "../Components" import "../Constants" -// Open Enable Coin Modal DefaultModal { id: root diff --git a/atomic_qt_design/qml/Wallet/ReceiveModal.qml b/atomic_qt_design/qml/Wallet/ReceiveModal.qml index d3ebd12ad7..9eb9b5e14b 100644 --- a/atomic_qt_design/qml/Wallet/ReceiveModal.qml +++ b/atomic_qt_design/qml/Wallet/ReceiveModal.qml @@ -5,7 +5,6 @@ import QtQuick.Controls 2.12 import "../Components" import "../Constants" -// Open Enable Coin Modal DefaultModal { id: root diff --git a/atomic_qt_design/qml/Wallet/SendModal.qml b/atomic_qt_design/qml/Wallet/SendModal.qml index 7a0adaa1b2..75d5c294a7 100644 --- a/atomic_qt_design/qml/Wallet/SendModal.qml +++ b/atomic_qt_design/qml/Wallet/SendModal.qml @@ -5,7 +5,6 @@ import QtQuick.Controls 2.12 import "../Components" import "../Constants" -// Open Enable Coin Modal DefaultModal { id: root From ca267b4db80a1bb797c23a09c0ab12b0525a9e45 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Wed, 29 Jul 2020 07:41:06 +0200 Subject: [PATCH 052/515] enhancements(orderbook): add proxy mdl Signed-off-by: romanszterg --- CMakeLists.txt | 1 + .../qml/Exchange/Trade/Orderbook.qml | 4 +- src/atomic.dex.qt.orderbook.model.cpp | 22 ++++++- src/atomic.dex.qt.orderbook.model.hpp | 15 +++-- src/atomic.dex.qt.orderbook.proxy.model.cpp | 58 +++++++++++++++++++ src/atomic.dex.qt.orderbook.proxy.model.hpp | 38 ++++++++++++ 6 files changed, 131 insertions(+), 7 deletions(-) create mode 100644 src/atomic.dex.qt.orderbook.proxy.model.cpp create mode 100644 src/atomic.dex.qt.orderbook.proxy.model.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 14a93cc132..b08a40cf9d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -162,6 +162,7 @@ target_sources(atomic_qt_shared_deps INTERFACE ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.contact.model.cpp ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.orderbook.cpp ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.orderbook.model.cpp + ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.orderbook.proxy.model.cpp ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.portfolio.model.cpp ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.portfolio.proxy.filter.model.cpp $<$:${CMAKE_SOURCE_DIR}/src/osx/atomic.dex.osx.manager.mm> diff --git a/atomic_qt_design/qml/Exchange/Trade/Orderbook.qml b/atomic_qt_design/qml/Exchange/Trade/Orderbook.qml index d999e2e3b5..adca3f3d62 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Orderbook.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Orderbook.qml @@ -14,7 +14,7 @@ InnerBackground { anchors.top: parent.top anchors.bottom: parent.bottom anchors.right: separator.left - model: API.get().orderbook.bids + model: API.get().orderbook.bids.proxy_mdl } VerticalLine { @@ -31,7 +31,7 @@ InnerBackground { anchors.left: separator.right is_asks: true - model: API.get().orderbook.asks + model: API.get().orderbook.asks.proxy_mdl } } } diff --git a/src/atomic.dex.qt.orderbook.model.cpp b/src/atomic.dex.qt.orderbook.model.cpp index 71bf0573e5..fda49bad74 100644 --- a/src/atomic.dex.qt.orderbook.model.cpp +++ b/src/atomic.dex.qt.orderbook.model.cpp @@ -35,10 +35,23 @@ namespace namespace atomic_dex { - orderbook_model::orderbook_model(kind orderbook_kind, QObject* parent) : QAbstractListModel(parent), m_current_orderbook_kind(orderbook_kind) + orderbook_model::orderbook_model(kind orderbook_kind, QObject* parent) : + QAbstractListModel(parent), m_current_orderbook_kind(orderbook_kind), m_model_proxy(new orderbook_proxy_model(this)) { spdlog::trace("{} l{} f[{}]", __FUNCTION__, __LINE__, fs::path(__FILE__).filename().string()); spdlog::trace("orderbook model created"); + + this->m_model_proxy->setSourceModel(this); + this->m_model_proxy->setDynamicSortFilter(true); + this->m_model_proxy->setSortRole(PriceRole); + if (this->m_current_orderbook_kind == kind::asks) + { + this->m_model_proxy->sort(0, Qt::DescendingOrder); + } + else + { + this->m_model_proxy->sort(0, Qt::AscendingOrder); + } } orderbook_model::~orderbook_model() noexcept @@ -183,6 +196,7 @@ namespace atomic_dex } } + // Deletion std::unordered_set to_remove; for (auto&& id: this->m_orders_id_registry) { @@ -236,4 +250,10 @@ namespace atomic_dex this->endResetModel(); emit lengthChanged(); } + + orderbook_proxy_model* + orderbook_model::get_orderbook_proxy() const noexcept + { + return m_model_proxy; + } } // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.orderbook.model.hpp b/src/atomic.dex.qt.orderbook.model.hpp index 759cc5ccf5..a3089730f9 100644 --- a/src/atomic.dex.qt.orderbook.model.hpp +++ b/src/atomic.dex.qt.orderbook.model.hpp @@ -16,9 +16,12 @@ #pragma once +//! QT #include +//! Project #include "atomic.dex.mm2.api.hpp" +#include "atomic.dex.qt.orderbook.proxy.model.hpp" namespace atomic_dex { @@ -26,6 +29,7 @@ namespace atomic_dex { Q_OBJECT Q_PROPERTY(int length READ get_length NOTIFY lengthChanged) + Q_PROPERTY(orderbook_proxy_model* proxy_mdl READ get_orderbook_proxy NOTIFY proxyMdlChanged) public: enum class kind { @@ -50,12 +54,14 @@ namespace atomic_dex bool setData(const QModelIndex& index, const QVariant& value, int role) final; bool removeRows(int row, int count, const QModelIndex& parent) override; - void reset_orderbook(const t_orderbook_answer& orderbook) noexcept; - void refresh_orderbook(const t_orderbook_answer& orderbook) noexcept; - void clear_orderbook() noexcept;; - [[nodiscard]] int get_length() const noexcept; + void reset_orderbook(const t_orderbook_answer& orderbook) noexcept; + void refresh_orderbook(const t_orderbook_answer& orderbook) noexcept; + void clear_orderbook() noexcept; + [[nodiscard]] int get_length() const noexcept; + [[nodiscard]] orderbook_proxy_model* get_orderbook_proxy() const noexcept; signals: void lengthChanged(); + void proxyMdlChanged(); private: void initialize_order(const ::mm2::api::order_contents& order) noexcept; @@ -65,6 +71,7 @@ namespace atomic_dex kind m_current_orderbook_kind{kind::asks}; t_orderbook_answer m_model_data; std::unordered_set m_orders_id_registry; + orderbook_proxy_model* m_model_proxy; }; } // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.orderbook.proxy.model.cpp b/src/atomic.dex.qt.orderbook.proxy.model.cpp new file mode 100644 index 0000000000..a714dc962e --- /dev/null +++ b/src/atomic.dex.qt.orderbook.proxy.model.cpp @@ -0,0 +1,58 @@ +/****************************************************************************** + * Copyright © 2013-2019 The Komodo Platform Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * Komodo Platform software, including this file may be copied, modified, * + * propagated or distributed except according to the terms contained in the * + * LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + +//! PCH +#include "atomic.dex.pch.hpp" + +//! Project +#include "atomic.dex.qt.orderbook.model.hpp" +#include "atomic.dex.qt.orderbook.proxy.model.hpp" + +namespace atomic_dex +{ + orderbook_proxy_model::orderbook_proxy_model(QObject* parent) : QSortFilterProxyModel(parent) + { + spdlog::trace("{} l{} f[{}]", __FUNCTION__, __LINE__, fs::path(__FILE__).filename().string()); + spdlog::trace("orderbook proxy model created"); + } + + orderbook_proxy_model::~orderbook_proxy_model() + { + spdlog::trace("{} l{} f[{}]", __FUNCTION__, __LINE__, fs::path(__FILE__).filename().string()); + spdlog::trace("orderbook proxy model destroyed"); + } + + bool + orderbook_proxy_model::lessThan(const QModelIndex& source_left, const QModelIndex& source_right) const + { + int role = this->sortRole(); + QVariant left_data = sourceModel()->data(source_left, role); + QVariant right_data = sourceModel()->data(source_right, role); + switch (static_cast(role)) + { + case orderbook_model::PriceRole: + return t_float_50(left_data.toString().toStdString()) < t_float_50(right_data.toString().toStdString()); + break; + case orderbook_model::QuantityRole: + break; + case orderbook_model::TotalRole: + break; + case orderbook_model::UUIDRole: + break; + } + return true; + } +} // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.orderbook.proxy.model.hpp b/src/atomic.dex.qt.orderbook.proxy.model.hpp new file mode 100644 index 0000000000..0b3d13687b --- /dev/null +++ b/src/atomic.dex.qt.orderbook.proxy.model.hpp @@ -0,0 +1,38 @@ +/****************************************************************************** + * Copyright © 2013-2019 The Komodo Platform Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * Komodo Platform software, including this file may be copied, modified, * + * propagated or distributed except according to the terms contained in the * + * LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + +#pragma once + +#include + +namespace atomic_dex +{ + class orderbook_proxy_model final : public QSortFilterProxyModel + { + Q_OBJECT + + public: + //! Constructor + orderbook_proxy_model(QObject* parent); + + //! Destructor + ~orderbook_proxy_model() final; + + protected: + //! Override member functions + [[nodiscard]] bool lessThan(const QModelIndex& source_left, const QModelIndex& source_right) const final;; + }; +} // namespace atomic_dex \ No newline at end of file From 7747d10820876eedd84e192f2ad64a2262b3ebe9 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Wed, 29 Jul 2020 08:13:46 +0200 Subject: [PATCH 053/515] enhancements(orderbook): finalize sort Signed-off-by: romanszterg --- src/atomic.dex.qt.orderbook.model.cpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/atomic.dex.qt.orderbook.model.cpp b/src/atomic.dex.qt.orderbook.model.cpp index fda49bad74..399f9f9fdc 100644 --- a/src/atomic.dex.qt.orderbook.model.cpp +++ b/src/atomic.dex.qt.orderbook.model.cpp @@ -44,14 +44,7 @@ namespace atomic_dex this->m_model_proxy->setSourceModel(this); this->m_model_proxy->setDynamicSortFilter(true); this->m_model_proxy->setSortRole(PriceRole); - if (this->m_current_orderbook_kind == kind::asks) - { - this->m_model_proxy->sort(0, Qt::DescendingOrder); - } - else - { - this->m_model_proxy->sort(0, Qt::AscendingOrder); - } + this->m_model_proxy->sort(0, Qt::DescendingOrder); } orderbook_model::~orderbook_model() noexcept From f4f25c3b3409a4839e2c6c010d1952efa231d4aa Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 29 Jul 2020 11:16:18 +0300 Subject: [PATCH 054/515] feat(gui): always open with the welcome page --- atomic_qt_design/qml/App.qml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/atomic_qt_design/qml/App.qml b/atomic_qt_design/qml/App.qml index 1cd8999a1c..68c2b2d181 100644 --- a/atomic_qt_design/qml/App.qml +++ b/atomic_qt_design/qml/App.qml @@ -12,7 +12,8 @@ Rectangle { color: Style.colorTheme8 function firstPage() { - return !API.get().first_run() && API.get().is_there_a_default_wallet() ? idx_login : idx_first_launch + return idx_login + //return !API.get().first_run() && API.get().is_there_a_default_wallet() ? idx_login : idx_first_launch } function cleanApp() { From 9675330430eeb4fdaa7674a0a9f7d4bef0cc8a88 Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 29 Jul 2020 11:18:15 +0300 Subject: [PATCH 055/515] feat(gui): revert welcome page change --- atomic_qt_design/qml/App.qml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/App.qml b/atomic_qt_design/qml/App.qml index 68c2b2d181..1cd8999a1c 100644 --- a/atomic_qt_design/qml/App.qml +++ b/atomic_qt_design/qml/App.qml @@ -12,8 +12,7 @@ Rectangle { color: Style.colorTheme8 function firstPage() { - return idx_login - //return !API.get().first_run() && API.get().is_there_a_default_wallet() ? idx_login : idx_first_launch + return !API.get().first_run() && API.get().is_there_a_default_wallet() ? idx_login : idx_first_launch } function cleanApp() { From 663b71e6649291f7eb0f90f6b445cfcdcb0a90ed Mon Sep 17 00:00:00 2001 From: romanszterg Date: Wed, 29 Jul 2020 12:22:10 +0200 Subject: [PATCH 056/515] enhancements(orderbook): add is_mine, price denom and price numer into QT Model Signed-off-by: romanszterg --- src/atomic.dex.mm2.api.cpp | 1 + src/atomic.dex.mm2.api.hpp | 1 + src/atomic.dex.qt.orderbook.model.cpp | 36 +++++++++++++++++---- src/atomic.dex.qt.orderbook.model.hpp | 5 ++- src/atomic.dex.qt.orderbook.proxy.model.cpp | 6 ++++ 5 files changed, 42 insertions(+), 7 deletions(-) diff --git a/src/atomic.dex.mm2.api.cpp b/src/atomic.dex.mm2.api.cpp index 318ccceed2..3baaaa2d37 100644 --- a/src/atomic.dex.mm2.api.cpp +++ b/src/atomic.dex.mm2.api.cpp @@ -409,6 +409,7 @@ namespace mm2::api j.at("age").get_to(contents.age); j.at("zcredits").get_to(contents.zcredits); j.at("uuid").get_to(contents.uuid); + j.at("is_mine").get_to(contents.is_mine); if (contents.price.find('.') != std::string::npos) { diff --git a/src/atomic.dex.mm2.api.hpp b/src/atomic.dex.mm2.api.hpp index 8595f77624..eb2eeceb7c 100644 --- a/src/atomic.dex.mm2.api.hpp +++ b/src/atomic.dex.mm2.api.hpp @@ -390,6 +390,7 @@ namespace mm2::api std::size_t zcredits; std::string total; std::string uuid; + bool is_mine; }; void from_json(const nlohmann::json& j, order_contents& contents); diff --git a/src/atomic.dex.qt.orderbook.model.cpp b/src/atomic.dex.qt.orderbook.model.cpp index 399f9f9fdc..2a25814ade 100644 --- a/src/atomic.dex.qt.orderbook.model.cpp +++ b/src/atomic.dex.qt.orderbook.model.cpp @@ -44,7 +44,14 @@ namespace atomic_dex this->m_model_proxy->setSourceModel(this); this->m_model_proxy->setDynamicSortFilter(true); this->m_model_proxy->setSortRole(PriceRole); - this->m_model_proxy->sort(0, Qt::DescendingOrder); + if (this->m_current_orderbook_kind == kind::asks) + { + this->m_model_proxy->sort(0, Qt::AscendingOrder); + } + else + { + this->m_model_proxy->sort(0, Qt::DescendingOrder); + } } orderbook_model::~orderbook_model() noexcept @@ -71,6 +78,12 @@ namespace atomic_dex case PriceRole: return m_current_orderbook_kind == kind::asks ? QString::fromStdString(m_model_data.asks.at(index.row()).price) : QString::fromStdString(m_model_data.bids.at(index.row()).price); + case PriceDenomRole: + return m_current_orderbook_kind == kind::asks ? QString::fromStdString(m_model_data.asks.at(index.row()).price_fraction_denom) + : QString::fromStdString(m_model_data.bids.at(index.row()).price_fraction_denom); + case PriceNumerRole: + return m_current_orderbook_kind == kind::asks ? QString::fromStdString(m_model_data.asks.at(index.row()).price_fraction_numer) + : QString::fromStdString(m_model_data.bids.at(index.row()).price_fraction_numer); case QuantityRole: return m_current_orderbook_kind == kind::asks ? QString::fromStdString(m_model_data.asks.at(index.row()).maxvolume) : QString::fromStdString(m_model_data.bids.at(index.row()).maxvolume); @@ -80,6 +93,8 @@ namespace atomic_dex case UUIDRole: return m_current_orderbook_kind == kind::asks ? QString::fromStdString(m_model_data.asks.at(index.row()).uuid) : QString::fromStdString(m_model_data.bids.at(index.row()).uuid); + case IsMineRole: + return m_current_orderbook_kind == kind::asks ? m_model_data.asks.at(index.row()).is_mine : m_model_data.bids.at(index.row()).is_mine; } } @@ -96,6 +111,15 @@ namespace atomic_dex case PriceRole: order.price = value.toString().toStdString(); break; + case PriceDenomRole: + order.price_fraction_denom = value.toString().toStdString(); + break; + case PriceNumerRole: + order.price_fraction_denom = value.toString().toStdString(); + break; + case IsMineRole: + order.is_mine = value.toBool(); + break; case QuantityRole: order.maxvolume = value.toString().toStdString(); break; @@ -113,7 +137,8 @@ namespace atomic_dex QHash orderbook_model::roleNames() const { - return {{PriceRole, "price"}, {QuantityRole, "quantity"}, {TotalRole, "total"}, {UUIDRole, "uuid"}}; + return {{PriceRole, "price"}, {QuantityRole, "quantity"}, {TotalRole, "total"}, {UUIDRole, "uuid"}, + {IsMineRole, "is_mine"}, {PriceDenomRole, "price_denom"}, {PriceNumerRole, "price_numer"}}; } void @@ -122,7 +147,6 @@ namespace atomic_dex this->beginResetModel(); m_model_data = orderbook; std::vector<::mm2::api::order_contents>& model_data = this->m_current_orderbook_kind == kind::asks ? this->m_model_data.asks : this->m_model_data.bids; - spdlog::trace("reset with orderbook of size: {}", model_data.size()); m_orders_id_registry.clear(); for (auto&& order: model_data) { @@ -164,6 +188,9 @@ namespace atomic_dex //! ID Found, update ! const QModelIndex& idx = res.at(0); update_value(OrderbookRoles::PriceRole, QString::fromStdString(order.price), idx, *this); + update_value(OrderbookRoles::PriceNumerRole, QString::fromStdString(order.price_fraction_numer), idx, *this); + update_value(OrderbookRoles::PriceDenomRole, QString::fromStdString(order.price_fraction_denom), idx, *this); + update_value(OrderbookRoles::IsMineRole, order.is_mine, idx, *this); update_value(OrderbookRoles::QuantityRole, QString::fromStdString(order.maxvolume), idx, *this); update_value(OrderbookRoles::TotalRole, QString::fromStdString(order.total), idx, *this); } @@ -178,13 +205,11 @@ namespace atomic_dex if (this->m_orders_id_registry.find(current_order.uuid) != this->m_orders_id_registry.end()) { //! Update - spdlog::trace("updating order id: {}", current_order.uuid); this->update_order(current_order); } else { //! Insertion - spdlog::trace("id {} not present in the registry, inserting", current_order.uuid); this->initialize_order(current_order); } } @@ -200,7 +225,6 @@ namespace atomic_dex auto res_list = this->match(index(0, 0), UUIDRole, QString::fromStdString(id)); if (not res_list.empty()) { - spdlog::trace("removing order from orderbook id: {}", id); this->removeRow(res_list.at(0).row()); to_remove.emplace(id); } diff --git a/src/atomic.dex.qt.orderbook.model.hpp b/src/atomic.dex.qt.orderbook.model.hpp index a3089730f9..1041283eb1 100644 --- a/src/atomic.dex.qt.orderbook.model.hpp +++ b/src/atomic.dex.qt.orderbook.model.hpp @@ -42,7 +42,10 @@ namespace atomic_dex PriceRole, QuantityRole, TotalRole, - UUIDRole + UUIDRole, + IsMineRole, + PriceDenomRole, + PriceNumerRole }; orderbook_model(kind orderbook_kind, QObject* parent = nullptr); diff --git a/src/atomic.dex.qt.orderbook.proxy.model.cpp b/src/atomic.dex.qt.orderbook.proxy.model.cpp index a714dc962e..a380377f21 100644 --- a/src/atomic.dex.qt.orderbook.proxy.model.cpp +++ b/src/atomic.dex.qt.orderbook.proxy.model.cpp @@ -52,6 +52,12 @@ namespace atomic_dex break; case orderbook_model::UUIDRole: break; + case orderbook_model::IsMineRole: + break; + case orderbook_model::PriceDenomRole: + break; + case orderbook_model::PriceNumerRole: + break; } return true; } From f73df09f12c82498d3625aca685ecd0535671e7d Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 29 Jul 2020 13:37:42 +0300 Subject: [PATCH 057/515] feat(gui): buy/sell to orderbook price header --- atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml index b425127715..6afca2a756 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml @@ -22,10 +22,11 @@ ColumnLayout { id: price_header font.pixelSize: Style.textSizeSmall2 - text_value: API.get().empty_string + (is_asks ? qsTr("Ask Price") + " (" + model.length + ")" : - "(" + model.length + ") " + qsTr("Bid Price")) + text_value: API.get().empty_string + (is_asks ? qsTr("Ask Price") + "\n(" + qsTr("Sell") + " " + getTicker(true) + ")" : + qsTr("Bid Price") + "\n(" + qsTr("Buy") + " " + getTicker(true) + ")") color: is_asks ? Style.colorRed : Style.colorGreen + horizontalAlignment: is_asks ? Text.AlignLeft : Text.AlignRight anchors.left: is_asks ? parent.left : undefined anchors.right: is_asks ? undefined : parent.right From ad32402ebfbab7e6dd4677fd6e3685fd637aa977 Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 29 Jul 2020 13:41:31 +0300 Subject: [PATCH 058/515] feat(gui): add tickers to orderbook quantity and total headers --- atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml index 6afca2a756..4bc1f72cd0 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml @@ -46,7 +46,7 @@ ColumnLayout { font.pixelSize: price_header.font.pixelSize - text_value: API.get().empty_string + (qsTr("Quantity")) + text_value: API.get().empty_string + (qsTr("Quantity") + "\n(" + getTicker(true) + ")") color: Style.colorWhite1 anchors.verticalCenter: parent.verticalCenter } @@ -61,7 +61,7 @@ ColumnLayout { font.pixelSize: price_header.font.pixelSize - text_value: API.get().empty_string + (qsTr("Total")) + text_value: API.get().empty_string + (qsTr("Total") + "\n(" + getTicker(false) + ")") color: Style.colorWhite1 anchors.verticalCenter: parent.verticalCenter } From 6600dc817b1e15d49fb253240d6ae2426d3f8404 Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 29 Jul 2020 13:50:20 +0300 Subject: [PATCH 059/515] feat(gui): align other headers --- atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml index 4bc1f72cd0..802506b499 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml @@ -44,6 +44,8 @@ ColumnLayout { anchors.leftMargin: is_asks ? parent.width * 0.32 : undefined anchors.rightMargin: is_asks ? undefined : parent.width * 0.32 + horizontalAlignment: price_header.horizontalAlignment + font.pixelSize: price_header.font.pixelSize text_value: API.get().empty_string + (qsTr("Quantity") + "\n(" + getTicker(true) + ")") @@ -59,6 +61,8 @@ ColumnLayout { anchors.leftMargin: is_asks ? parent.width * 0.65 : undefined anchors.rightMargin: is_asks ? undefined : parent.width * 0.65 + horizontalAlignment: price_header.horizontalAlignment + font.pixelSize: price_header.font.pixelSize text_value: API.get().empty_string + (qsTr("Total") + "\n(" + getTicker(false) + ")") From 18204b867068245abb3a572632bf94c94a1c4c2c Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 29 Jul 2020 14:00:15 +0300 Subject: [PATCH 060/515] feat(gui): add price header ticker --- atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml index 802506b499..848ea57e44 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml @@ -22,8 +22,8 @@ ColumnLayout { id: price_header font.pixelSize: Style.textSizeSmall2 - text_value: API.get().empty_string + (is_asks ? qsTr("Ask Price") + "\n(" + qsTr("Sell") + " " + getTicker(true) + ")" : - qsTr("Bid Price") + "\n(" + qsTr("Buy") + " " + getTicker(true) + ")") + text_value: API.get().empty_string + (is_asks ? qsTr("Ask Price") + "\n(" + getTicker(false) + ")": + qsTr("Bid Price") + "\n(" + getTicker(false) + ")") color: is_asks ? Style.colorRed : Style.colorGreen horizontalAlignment: is_asks ? Text.AlignLeft : Text.AlignRight From b27488794511ac62af8ab3025ae58f32692557b7 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Wed, 29 Jul 2020 13:01:26 +0200 Subject: [PATCH 061/515] enhancements(orderbook): add depth part Signed-off-by: romanszterg --- src/atomic.dex.mm2.api.cpp | 12 ++++++++++++ src/atomic.dex.mm2.api.hpp | 2 ++ src/atomic.dex.qt.orderbook.model.cpp | 22 ++++++++++++++++++++-- src/atomic.dex.qt.orderbook.model.hpp | 3 ++- 4 files changed, 36 insertions(+), 3 deletions(-) diff --git a/src/atomic.dex.mm2.api.cpp b/src/atomic.dex.mm2.api.cpp index 3baaaa2d37..03bb8da1bd 100644 --- a/src/atomic.dex.mm2.api.cpp +++ b/src/atomic.dex.mm2.api.cpp @@ -440,6 +440,18 @@ namespace mm2::api sys_time tp{std::chrono::milliseconds{answer.timestamp}}; auto tp_zoned = date::make_zoned(current_zone(), tp); answer.human_timestamp = date::format("%Y-%m-%d %I:%M:%S", tp_zoned); + + t_float_50 asks_total_f("0"); + t_float_50 res_asks = std::accumulate(begin(answer.asks), end(answer.asks), asks_total_f, [](const t_float_50& sum, const order_contents& contents) { + return sum + t_float_50(contents.total); + }); + answer.asks_total_volume = adjust_precision(res_asks.str()); + + t_float_50 bids_total_f("0"); + t_float_50 res_bids = std::accumulate(begin(answer.bids), end(answer.bids), bids_total_f, [](const t_float_50& sum, const order_contents& contents) { + return sum + t_float_50(contents.total); + }); + answer.bids_total_volume = adjust_precision(res_bids.str()); } void diff --git a/src/atomic.dex.mm2.api.hpp b/src/atomic.dex.mm2.api.hpp index eb2eeceb7c..cf43333ce0 100644 --- a/src/atomic.dex.mm2.api.hpp +++ b/src/atomic.dex.mm2.api.hpp @@ -408,6 +408,8 @@ namespace mm2::api std::size_t timestamp; std::size_t netid; std::string human_timestamp; //! Moment of the orderbook request human readeable + std::string asks_total_volume; + std::string bids_total_volume; //! Internal std::string raw_result; diff --git a/src/atomic.dex.qt.orderbook.model.cpp b/src/atomic.dex.qt.orderbook.model.cpp index 2a25814ade..f21775d5c2 100644 --- a/src/atomic.dex.qt.orderbook.model.cpp +++ b/src/atomic.dex.qt.orderbook.model.cpp @@ -95,6 +95,15 @@ namespace atomic_dex : QString::fromStdString(m_model_data.bids.at(index.row()).uuid); case IsMineRole: return m_current_orderbook_kind == kind::asks ? m_model_data.asks.at(index.row()).is_mine : m_model_data.bids.at(index.row()).is_mine; + case PercentDepthRole: + { + const std::vector<::mm2::api::order_contents>& model_data = + this->m_current_orderbook_kind == kind::asks ? this->m_model_data.asks : this->m_model_data.bids; + const std::string& current_max_depth = + this->m_current_orderbook_kind == kind::asks ? this->m_model_data.asks_total_volume : this->m_model_data.bids_total_volume; + t_float_50 final = t_float_50(model_data.at(index.row()).total) / t_float_50(current_max_depth); + return QString::fromStdString(adjust_precision(final.str())); + } } } @@ -129,6 +138,8 @@ namespace atomic_dex case UUIDRole: order.uuid = value.toString().toStdString(); break; + default: + return false; } emit dataChanged(index, index, {role}); return true; @@ -137,8 +148,15 @@ namespace atomic_dex QHash orderbook_model::roleNames() const { - return {{PriceRole, "price"}, {QuantityRole, "quantity"}, {TotalRole, "total"}, {UUIDRole, "uuid"}, - {IsMineRole, "is_mine"}, {PriceDenomRole, "price_denom"}, {PriceNumerRole, "price_numer"}}; + return { + {PriceRole, "price"}, + {QuantityRole, "quantity"}, + {TotalRole, "total"}, + {UUIDRole, "uuid"}, + {IsMineRole, "is_mine"}, + {PriceDenomRole, "price_denom"}, + {PriceNumerRole, "price_numer"}, + {PercentDepthRole, "depth"}}; } void diff --git a/src/atomic.dex.qt.orderbook.model.hpp b/src/atomic.dex.qt.orderbook.model.hpp index 1041283eb1..b6e242e5b2 100644 --- a/src/atomic.dex.qt.orderbook.model.hpp +++ b/src/atomic.dex.qt.orderbook.model.hpp @@ -45,7 +45,8 @@ namespace atomic_dex UUIDRole, IsMineRole, PriceDenomRole, - PriceNumerRole + PriceNumerRole, + PercentDepthRole }; orderbook_model(kind orderbook_kind, QObject* parent = nullptr); From e5ad7e57b5dd7f696e3b77f1098e82aff0254f5c Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 29 Jul 2020 14:26:37 +0300 Subject: [PATCH 062/515] feat(gui): add depth line --- .../qml/Exchange/Trade/OrderbookSection.qml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml index 848ea57e44..d9b06ed96f 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml @@ -93,6 +93,16 @@ ColumnLayout { width: root.width height: 20 + Rectangle { + width: parent.width * depth + height: parent.height + color: price_value.color + opacity: 0.2 + + anchors.left: is_asks ? parent.left : undefined + anchors.right: is_asks ? undefined : parent.right + } + MouseArea { id: mouse_area anchors.fill: parent From e2b49a604b31bfae89b1a1d293d5b1cf020fa072 Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 29 Jul 2020 14:28:34 +0300 Subject: [PATCH 063/515] feat(gui): don't format price at orderbook --- atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml index d9b06ed96f..974abcf997 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml @@ -121,7 +121,7 @@ ColumnLayout { font.pixelSize: Style.textSizeSmall1 - text_value: API.get().empty_string + (General.formatDouble(price)) + text_value: API.get().empty_string + (price) color: price_header.color anchors.verticalCenter: parent.verticalCenter } From 658f00f4cff3757bd103a362cabdf8349442545e Mon Sep 17 00:00:00 2001 From: romanszterg Date: Wed, 29 Jul 2020 13:29:10 +0200 Subject: [PATCH 064/515] enhancements(orderbook): add depth part as a field Signed-off-by: romanszterg --- src/atomic.dex.mm2.api.cpp | 10 ++++++++++ src/atomic.dex.mm2.api.hpp | 1 + src/atomic.dex.qt.orderbook.model.cpp | 16 ++++++---------- src/atomic.dex.qt.orderbook.proxy.model.cpp | 2 ++ 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/atomic.dex.mm2.api.cpp b/src/atomic.dex.mm2.api.cpp index 03bb8da1bd..5a1d6e0036 100644 --- a/src/atomic.dex.mm2.api.cpp +++ b/src/atomic.dex.mm2.api.cpp @@ -452,6 +452,16 @@ namespace mm2::api return sum + t_float_50(contents.total); }); answer.bids_total_volume = adjust_precision(res_bids.str()); + for (auto&& cur_asks : answer.asks) + { + t_float_50 percent_f = t_float_50(cur_asks.total) / res_asks; + cur_asks.depth_percent = adjust_precision(percent_f.str()); + } + for (auto&& cur_bids : answer.bids) + { + t_float_50 percent_f = t_float_50(cur_bids.total) / res_bids; + cur_bids.depth_percent = adjust_precision(percent_f.str()); + } } void diff --git a/src/atomic.dex.mm2.api.hpp b/src/atomic.dex.mm2.api.hpp index cf43333ce0..5b2a0ae638 100644 --- a/src/atomic.dex.mm2.api.hpp +++ b/src/atomic.dex.mm2.api.hpp @@ -390,6 +390,7 @@ namespace mm2::api std::size_t zcredits; std::string total; std::string uuid; + std::string depth_percent; bool is_mine; }; diff --git a/src/atomic.dex.qt.orderbook.model.cpp b/src/atomic.dex.qt.orderbook.model.cpp index f21775d5c2..9853d76e21 100644 --- a/src/atomic.dex.qt.orderbook.model.cpp +++ b/src/atomic.dex.qt.orderbook.model.cpp @@ -96,14 +96,8 @@ namespace atomic_dex case IsMineRole: return m_current_orderbook_kind == kind::asks ? m_model_data.asks.at(index.row()).is_mine : m_model_data.bids.at(index.row()).is_mine; case PercentDepthRole: - { - const std::vector<::mm2::api::order_contents>& model_data = - this->m_current_orderbook_kind == kind::asks ? this->m_model_data.asks : this->m_model_data.bids; - const std::string& current_max_depth = - this->m_current_orderbook_kind == kind::asks ? this->m_model_data.asks_total_volume : this->m_model_data.bids_total_volume; - t_float_50 final = t_float_50(model_data.at(index.row()).total) / t_float_50(current_max_depth); - return QString::fromStdString(adjust_precision(final.str())); - } + return m_current_orderbook_kind == kind::asks ? QString::fromStdString(m_model_data.asks.at(index.row()).depth_percent) + : QString::fromStdString(m_model_data.bids.at(index.row()).depth_percent); } } @@ -138,8 +132,9 @@ namespace atomic_dex case UUIDRole: order.uuid = value.toString().toStdString(); break; - default: - return false; + case PercentDepthRole: + order.depth_percent = value.toString().toStdString(); + break; } emit dataChanged(index, index, {role}); return true; @@ -211,6 +206,7 @@ namespace atomic_dex update_value(OrderbookRoles::IsMineRole, order.is_mine, idx, *this); update_value(OrderbookRoles::QuantityRole, QString::fromStdString(order.maxvolume), idx, *this); update_value(OrderbookRoles::TotalRole, QString::fromStdString(order.total), idx, *this); + update_value(OrderbookRoles::PercentDepthRole, QString::fromStdString(order.depth_percent), idx, *this); } } diff --git a/src/atomic.dex.qt.orderbook.proxy.model.cpp b/src/atomic.dex.qt.orderbook.proxy.model.cpp index a380377f21..51a07ca1c2 100644 --- a/src/atomic.dex.qt.orderbook.proxy.model.cpp +++ b/src/atomic.dex.qt.orderbook.proxy.model.cpp @@ -58,6 +58,8 @@ namespace atomic_dex break; case orderbook_model::PriceNumerRole: break; + case orderbook_model::PercentDepthRole: + break; } return true; } From 7991e5d3c33bfac13a306c66146695b2d310d831 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Wed, 29 Jul 2020 13:45:15 +0200 Subject: [PATCH 065/515] enhancements(orderbook): update depth part as a field Signed-off-by: romanszterg --- src/atomic.dex.mm2.api.cpp | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/atomic.dex.mm2.api.cpp b/src/atomic.dex.mm2.api.cpp index 5a1d6e0036..9808c2e5c1 100644 --- a/src/atomic.dex.mm2.api.cpp +++ b/src/atomic.dex.mm2.api.cpp @@ -440,26 +440,30 @@ namespace mm2::api sys_time tp{std::chrono::milliseconds{answer.timestamp}}; auto tp_zoned = date::make_zoned(current_zone(), tp); answer.human_timestamp = date::format("%Y-%m-%d %I:%M:%S", tp_zoned); + + t_float_50 result_asks_f("0"); + for (auto&& cur_asks : answer.asks) { + result_asks_f = result_asks_f + t_float_50(cur_asks.total); + } + + answer.asks_total_volume = result_asks_f.str(); + spdlog::trace("result is: {}", answer.asks_total_volume); - t_float_50 asks_total_f("0"); - t_float_50 res_asks = std::accumulate(begin(answer.asks), end(answer.asks), asks_total_f, [](const t_float_50& sum, const order_contents& contents) { - return sum + t_float_50(contents.total); - }); - answer.asks_total_volume = adjust_precision(res_asks.str()); - - t_float_50 bids_total_f("0"); - t_float_50 res_bids = std::accumulate(begin(answer.bids), end(answer.bids), bids_total_f, [](const t_float_50& sum, const order_contents& contents) { - return sum + t_float_50(contents.total); - }); - answer.bids_total_volume = adjust_precision(res_bids.str()); + t_float_50 result_bids_f("0"); + for (auto&& cur_bids : answer.bids) { + result_bids_f = result_bids_f + t_float_50(cur_bids.total); + } + + answer.bids_total_volume = result_bids_f.str(); for (auto&& cur_asks : answer.asks) { - t_float_50 percent_f = t_float_50(cur_asks.total) / res_asks; + t_float_50 percent_f = t_float_50(cur_asks.total) / result_asks_f; cur_asks.depth_percent = adjust_precision(percent_f.str()); } + for (auto&& cur_bids : answer.bids) { - t_float_50 percent_f = t_float_50(cur_bids.total) / res_bids; + t_float_50 percent_f = t_float_50(cur_bids.total) / result_bids_f; cur_bids.depth_percent = adjust_precision(percent_f.str()); } } From fb76aa394ffca5a266781b2d14b13cd23265e42a Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 29 Jul 2020 14:50:03 +0300 Subject: [PATCH 066/515] feat(gui): add hover effect to lines --- .../qml/Exchange/Trade/OrderbookSection.qml | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml index 974abcf997..416720a8e1 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml @@ -87,17 +87,26 @@ ColumnLayout { Layout.fillWidth: true Layout.fillHeight: true - delegate: Rectangle { - color: /*mouse_area.containsMouse ? Style.colorTheme4 : */"transparent" - + delegate: Item { width: root.width height: 20 + Rectangle { + visible: mouse_area.containsMouse + width: parent.width + height: parent.height + color: Style.colorWhite1 + opacity: 0.2 + + anchors.left: is_asks ? parent.left : undefined + anchors.right: is_asks ? undefined : parent.right + } + Rectangle { width: parent.width * depth height: parent.height color: price_value.color - opacity: 0.2 + opacity: 0.1 anchors.left: is_asks ? parent.left : undefined anchors.right: is_asks ? undefined : parent.right @@ -121,7 +130,7 @@ ColumnLayout { font.pixelSize: Style.textSizeSmall1 - text_value: API.get().empty_string + (price) + text_value: API.get().empty_string + (General.formatDouble(price)) color: price_header.color anchors.verticalCenter: parent.verticalCenter } From e6bf92c6c06618d376e173ff0a0ff2a04f9849b3 Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 29 Jul 2020 14:57:32 +0300 Subject: [PATCH 067/515] feat(gui): fix first bar is a bit larger --- atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml index 416720a8e1..00d5ec05bb 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml @@ -11,6 +11,8 @@ ColumnLayout { property bool is_asks: false property alias model: list.model + spacing: 0 + // List header Item { Layout.fillWidth: true From 0440695af52de5a4ed8be8a8883f7d832f785ff8 Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 29 Jul 2020 15:05:20 +0300 Subject: [PATCH 068/515] feat(gui): select from order bid section --- .../qml/Exchange/Trade/OrderbookSection.qml | 8 ++++++-- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 10 +++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml index 00d5ec05bb..1d41aeeb15 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml @@ -94,7 +94,7 @@ ColumnLayout { height: 20 Rectangle { - visible: mouse_area.containsMouse + visible: mouse_area.containsMouse && !is_mine width: parent.width height: parent.height color: Style.colorWhite1 @@ -118,7 +118,11 @@ ColumnLayout { id: mouse_area anchors.fill: parent hoverEnabled: true - //onClicked: selectOrder(model.modelData) + onClicked: { + if(is_mine) return + + if(!is_asks) selectOrder(price, quantity, price_denom, price_numer) + } } // Price diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index aa9e618d8c..e1a7e3f2f2 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -50,11 +50,11 @@ Item { preffered_order = General.clone(empty_order) } - function selectOrder(order) { - preffered_order.price = order.price - preffered_order.volume = order.volume - preffered_order.price_denom = order.price_denom - preffered_order.price_numer = order.price_numer + function selectOrder(price, quantity, price_denom, price_numer) { + preffered_order.price = price + preffered_order.volume = quantity + preffered_order.price_denom = price_denom + preffered_order.price_numer = price_numer preffered_order = preffered_order updateRelAmount() } From 5dd6782e9789e1655283429dfed5fe86fac79117 Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 29 Jul 2020 15:52:31 +0300 Subject: [PATCH 069/515] feat(gui): new selected price and unlock implementation --- .../qml/Exchange/Trade/OrderForm.qml | 33 +++++++++---------- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 3 +- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index 30455998bf..719ec3fc72 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -280,6 +280,15 @@ FloatingBackground { } } + function resetPrice() { + if(!my_side && orderIsSelected()) resetPreferredPrice() + } + + field.onPressed: resetPrice() + field.onFocusChanged: { + if(field.activeFocus) resetPrice() + } + field.font.pixelSize: Style.textSizeSmall1 field.font.weight: Font.Bold } @@ -439,29 +448,19 @@ FloatingBackground { } } - - RowLayout { + // Trade button + DefaultButton { Layout.alignment: Qt.AlignRight | Qt.AlignBottom Layout.topMargin: 5 Layout.rightMargin: top_line.Layout.rightMargin Layout.bottomMargin: layout_margin - DefaultButton { - visible: orderIsSelected() + visible: !my_side + width: 170 - text: API.get().empty_string + (qsTr("Unlock Price")) - onClicked: resetPreferredPrice() - } - - // Trade button - DefaultButton { - visible: !my_side - width: 170 - - text: API.get().empty_string + (qsTr("Trade")) - enabled: valid_trade_info && !notEnoughBalanceForFees() && form_base.isValid() && form_rel.isValid() - onClicked: confirm_trade_modal.open() - } + text: API.get().empty_string + (orderIsSelected() ? qsTr("Match Order") : qsTr("Create Order")) + enabled: valid_trade_info && !notEnoughBalanceForFees() && form_base.isValid() && form_rel.isValid() + onClicked: confirm_trade_modal.open() } } } diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index e1a7e3f2f2..e705057d53 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -57,6 +57,7 @@ Item { preffered_order.price_numer = price_numer preffered_order = preffered_order updateRelAmount() + form_base.field.forceActiveFocus() } function newRelVolume(price) { @@ -399,8 +400,6 @@ Item { anchors.right: parent.right anchors.top: form_base.bottom anchors.topMargin: layout_margin - - field.enabled: enabled && !orderIsSelected() } // Show errors From bcadd8fde2ca178f5604ff4f4db7376e6fd71cd5 Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 29 Jul 2020 16:09:34 +0300 Subject: [PATCH 070/515] feat(gui): select order from asks side --- .../qml/Exchange/Trade/OrderForm.qml | 2 +- .../qml/Exchange/Trade/OrderbookSection.qml | 2 +- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 29 ++++++++++--------- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index 719ec3fc72..51c17e54c3 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -458,7 +458,7 @@ FloatingBackground { visible: !my_side width: 170 - text: API.get().empty_string + (orderIsSelected() ? qsTr("Match Order") : qsTr("Create Order")) + text: API.get().empty_string + (!preffered_order.is_asks && orderIsSelected() ? qsTr("Match Order") : qsTr("Create Order")) enabled: valid_trade_info && !notEnoughBalanceForFees() && form_base.isValid() && form_rel.isValid() onClicked: confirm_trade_modal.open() } diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml index 1d41aeeb15..8b6b344918 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml @@ -121,7 +121,7 @@ ColumnLayout { onClicked: { if(is_mine) return - if(!is_asks) selectOrder(price, quantity, price_denom, price_numer) + selectOrder(is_asks, price, quantity, price_denom, price_numer) } } diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index e705057d53..f70baa0d30 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -38,7 +38,7 @@ Item { cex_price = API.get().get_cex_rates(base, rel) } - readonly property var empty_order: ({ "price": "0","price_denom":"0","price_numer":"0","volume":"0"}) + readonly property var empty_order: ({ "is_asks":false,"price":"0","price_denom":"0","price_numer":"0","volume":"0"}) property var preffered_order: General.clone(empty_order) @@ -50,7 +50,8 @@ Item { preffered_order = General.clone(empty_order) } - function selectOrder(price, quantity, price_denom, price_numer) { + function selectOrder(is_asks, price, quantity, price_denom, price_numer) { + preffered_order.is_asks = is_asks preffered_order.price = price preffered_order.volume = quantity preffered_order.price_denom = price_denom @@ -69,17 +70,19 @@ Item { const price = parseFloat(preffered_order.price) let new_rel = newRelVolume(preffered_order.price) - // If new rel volume is higher than the order max volume - const max_volume = parseFloat(preffered_order.volume) - if(new_rel > max_volume) { - new_rel = max_volume - - // Set base - const max_base_volume = max_volume / price - if(parseFloat(form_base.getVolume()) !== max_base_volume) { - const new_base_text = General.formatDouble(max_base_volume) - if(form_base.field.text !== new_base_text) - form_base.field.text = new_base_text + if(!preffered_order.is_asks) { + // If new rel volume is higher than the order max volume + const max_volume = parseFloat(preffered_order.volume) + if(new_rel > max_volume) { + new_rel = max_volume + + // Set base + const max_base_volume = max_volume / price + if(parseFloat(form_base.getVolume()) !== max_base_volume) { + const new_base_text = General.formatDouble(max_base_volume) + if(form_base.field.text !== new_base_text) + form_base.field.text = new_base_text + } } } From e8e9de7925c6a1fa8457252ffc55f3889e707fae Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 29 Jul 2020 16:32:09 +0300 Subject: [PATCH 071/515] feat(gui): show my order in the order book --- atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml index 8b6b344918..b0bbdb63b6 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml @@ -93,17 +93,19 @@ ColumnLayout { width: root.width height: 20 + // Hover / My Order line Rectangle { - visible: mouse_area.containsMouse && !is_mine + visible: mouse_area.containsMouse || is_mine width: parent.width height: parent.height - color: Style.colorWhite1 - opacity: 0.2 + color: is_mine ? Style.colorOrange : Style.colorWhite1 + opacity: 0.1 anchors.left: is_asks ? parent.left : undefined anchors.right: is_asks ? undefined : parent.right } + // Depth line Rectangle { width: parent.width * depth height: parent.height From fcac4acc25a537ac876126e7c02cf2851d3fad09 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Wed, 29 Jul 2020 15:42:28 +0200 Subject: [PATCH 072/515] enhancements(orderbook): replace total by quantity for depth calculation Signed-off-by: romanszterg --- src/atomic.dex.mm2.api.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/atomic.dex.mm2.api.cpp b/src/atomic.dex.mm2.api.cpp index 9808c2e5c1..9927270b59 100644 --- a/src/atomic.dex.mm2.api.cpp +++ b/src/atomic.dex.mm2.api.cpp @@ -443,27 +443,26 @@ namespace mm2::api t_float_50 result_asks_f("0"); for (auto&& cur_asks : answer.asks) { - result_asks_f = result_asks_f + t_float_50(cur_asks.total); + result_asks_f = result_asks_f + t_float_50(cur_asks.maxvolume); } answer.asks_total_volume = result_asks_f.str(); - spdlog::trace("result is: {}", answer.asks_total_volume); t_float_50 result_bids_f("0"); for (auto&& cur_bids : answer.bids) { - result_bids_f = result_bids_f + t_float_50(cur_bids.total); + result_bids_f = result_bids_f + t_float_50(cur_bids.maxvolume); } answer.bids_total_volume = result_bids_f.str(); for (auto&& cur_asks : answer.asks) { - t_float_50 percent_f = t_float_50(cur_asks.total) / result_asks_f; + t_float_50 percent_f = t_float_50(cur_asks.maxvolume) / result_asks_f; cur_asks.depth_percent = adjust_precision(percent_f.str()); } for (auto&& cur_bids : answer.bids) { - t_float_50 percent_f = t_float_50(cur_bids.total) / result_bids_f; + t_float_50 percent_f = t_float_50(cur_bids.maxvolume) / result_bids_f; cur_bids.depth_percent = adjust_precision(percent_f.str()); } } From 3aa814779342d1428b8d78cbe3fad2a93c87aee0 Mon Sep 17 00:00:00 2001 From: milerius Date: Wed, 29 Jul 2020 17:12:17 +0200 Subject: [PATCH 073/515] feat(login): dont set default wallet name during wallet creation --- src/atomic.dex.qt.wallet.manager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/atomic.dex.qt.wallet.manager.cpp b/src/atomic.dex.qt.wallet.manager.cpp index 17c346ee23..affa0e47b9 100644 --- a/src/atomic.dex.qt.wallet.manager.cpp +++ b/src/atomic.dex.qt.wallet.manager.cpp @@ -84,7 +84,7 @@ namespace atomic_dex std::ofstream ofs((get_atomic_dex_config_folder() / "default.wallet"s).string().c_str()); ofs << wallet_name.toStdString(); - set_wallet_default_name(wallet_name); + //set_wallet_default_name(wallet_name); std::ofstream wallet_object(wallet_object_path.string()); nlohmann::json wallet_object_json; From 40641cd6a1842b5deeac9de8b6b175c4bf319033 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Wed, 29 Jul 2020 19:22:49 +0200 Subject: [PATCH 074/515] enhancements(login): better login policy Signed-off-by: romanszterg --- src/atomic.dex.app.cpp | 10 ++++++++-- src/atomic.dex.qt.wallet.manager.cpp | 6 ++++++ src/atomic.dex.qt.wallet.manager.hpp | 1 + 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index fc9bd61f40..e57cb75d1b 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -1387,8 +1387,14 @@ namespace atomic_dex bool application::login(const QString& password, const QString& wallet_name) { - bool res = m_wallet_manager.login(password, wallet_name, get_mm2(), [this]() { this->set_status("initializing_mm2"); }); - this->m_addressbook->initializeFromCfg(); + bool res = m_wallet_manager.login(password, wallet_name, get_mm2(), [this, &wallet_name]() { + this->set_wallet_default_name(wallet_name); + this->set_status("initializing_mm2"); + }); + if (res) + { + this->m_addressbook->initializeFromCfg(); + } return res; } diff --git a/src/atomic.dex.qt.wallet.manager.cpp b/src/atomic.dex.qt.wallet.manager.cpp index affa0e47b9..bcd47b1e04 100644 --- a/src/atomic.dex.qt.wallet.manager.cpp +++ b/src/atomic.dex.qt.wallet.manager.cpp @@ -313,4 +313,10 @@ namespace atomic_dex { return m_wallet_cfg; } + + void + qt_wallet_manager::just_set_wallet_name(QString wallet_name) + { + this->m_current_default_wallet = wallet_name; + } } // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.wallet.manager.hpp b/src/atomic.dex.qt.wallet.manager.hpp index bb725c512a..3e1c580f7d 100644 --- a/src/atomic.dex.qt.wallet.manager.hpp +++ b/src/atomic.dex.qt.wallet.manager.hpp @@ -35,6 +35,7 @@ namespace atomic_dex { public: QString get_wallet_default_name() const noexcept; + void just_set_wallet_name(QString wallet_name); void set_wallet_default_name(QString wallet_name) noexcept; From 0fd99fa3b00cf0c46df67f9346a5b2020618387e Mon Sep 17 00:00:00 2001 From: romanszterg Date: Wed, 29 Jul 2020 19:32:21 +0200 Subject: [PATCH 075/515] enhancements(login): clear login on disconnect Signed-off-by: romanszterg --- src/atomic.dex.app.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index e57cb75d1b..c812a2bb99 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -878,6 +878,7 @@ namespace atomic_dex this->m_need_a_full_refresh_of_mm2 = true; + this->m_wallet_manager.just_set_wallet_name(""); return fs::remove(get_atomic_dex_config_folder() / "default.wallet"); } From 3fe211d98628bdac39f4a4319e872ae964334762 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Wed, 29 Jul 2020 19:34:30 +0200 Subject: [PATCH 076/515] enhancements(login): emit wallet change Signed-off-by: romanszterg --- src/atomic.dex.app.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index c812a2bb99..ed34eebbbf 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -879,6 +879,7 @@ namespace atomic_dex this->m_need_a_full_refresh_of_mm2 = true; this->m_wallet_manager.just_set_wallet_name(""); + emit on_wallet_default_name_changed(); return fs::remove(get_atomic_dex_config_folder() / "default.wallet"); } From 2169a2182474e12f4dfa893fea6dec14005d6c8d Mon Sep 17 00:00:00 2001 From: romanszterg Date: Wed, 29 Jul 2020 19:43:38 +0200 Subject: [PATCH 077/515] enhancements(login): comments default wallet Signed-off-by: romanszterg --- src/atomic.dex.qt.wallet.manager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/atomic.dex.qt.wallet.manager.cpp b/src/atomic.dex.qt.wallet.manager.cpp index bcd47b1e04..70dc865cfd 100644 --- a/src/atomic.dex.qt.wallet.manager.cpp +++ b/src/atomic.dex.qt.wallet.manager.cpp @@ -81,8 +81,8 @@ namespace atomic_dex // sodium_memzero(&seed, seed.size()); sodium_memzero(key.data(), key.size()); - std::ofstream ofs((get_atomic_dex_config_folder() / "default.wallet"s).string().c_str()); - ofs << wallet_name.toStdString(); + //std::ofstream ofs((get_atomic_dex_config_folder() / "default.wallet"s).string().c_str()); + //ofs << wallet_name.toStdString(); //set_wallet_default_name(wallet_name); From aa072c4e3fea4e99cdabbc4aa933369b84ac2650 Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 29 Jul 2020 20:44:46 +0300 Subject: [PATCH 078/515] feat(gui): set default wallet new implementation --- atomic_qt_design/qml/App.qml | 9 ++++++--- atomic_qt_design/qml/Screens/FirstLaunch.qml | 2 +- atomic_qt_design/qml/Screens/Login.qml | 6 +++--- atomic_qt_design/qml/Screens/NewUser.qml | 1 + atomic_qt_design/qml/Screens/RecoverSeed.qml | 1 + 5 files changed, 12 insertions(+), 7 deletions(-) diff --git a/atomic_qt_design/qml/App.qml b/atomic_qt_design/qml/App.qml index 1cd8999a1c..c1d5e2cb69 100644 --- a/atomic_qt_design/qml/App.qml +++ b/atomic_qt_design/qml/App.qml @@ -11,6 +11,8 @@ Rectangle { color: Style.colorTheme8 + property string selected_wallet_name: "" + function firstPage() { return !API.get().first_run() && API.get().is_there_a_default_wallet() ? idx_login : idx_first_launch } @@ -21,7 +23,8 @@ Rectangle { function onDisconnect() { openFirstLaunch() } - function openFirstLaunch(force) { + function openFirstLaunch(force=false, set_wallet_name=true) { + if(set_wallet_name) selected_wallet_name = API.get().wallet_default_name cleanApp() if(API.design_editor) { @@ -70,13 +73,13 @@ Rectangle { RecoverSeed { onClickedBack: () => { openFirstLaunch() } - postConfirmSuccess: () => { openFirstLaunch() } + postConfirmSuccess: () => { openFirstLaunch(false, false) } } NewUser { id: new_user onClickedBack: () => { openFirstLaunch() } - postCreateSuccess: () => { openFirstLaunch() } + postCreateSuccess: () => { openFirstLaunch(false, false) } } Login { diff --git a/atomic_qt_design/qml/Screens/FirstLaunch.qml b/atomic_qt_design/qml/Screens/FirstLaunch.qml index cd0effef16..ed23af25a3 100644 --- a/atomic_qt_design/qml/Screens/FirstLaunch.qml +++ b/atomic_qt_design/qml/Screens/FirstLaunch.qml @@ -88,7 +88,7 @@ SetupPage { anchors.fill: parent hoverEnabled: true onClicked: { - API.get().wallet_default_name = model.modelData + selected_wallet_name = model.modelData onClickedWallet() } } diff --git a/atomic_qt_design/qml/Screens/Login.qml b/atomic_qt_design/qml/Screens/Login.qml index eeb147a60f..cf277b8dfa 100644 --- a/atomic_qt_design/qml/Screens/Login.qml +++ b/atomic_qt_design/qml/Screens/Login.qml @@ -17,7 +17,7 @@ SetupPage { } function onClickedLogin(password) { - if(API.get().login(password, API.get().wallet_default_name)) { + if(API.get().login(password, selected_wallet_name)) { console.log("Success: Login") postLoginSuccess() return true @@ -52,7 +52,7 @@ SetupPage { width: 400 DefaultText { - text_value: API.get().empty_string + (qsTr("Login") + ": " + API.get().wallet_default_name) + text_value: API.get().empty_string + (qsTr("Login") + ": " + selected_wallet_name) } HorizontalLine { @@ -72,7 +72,7 @@ SetupPage { text: API.get().empty_string + (qsTr("Back")) Layout.fillWidth: true onClicked: { - API.get().wallet_default_name = "" + selected_wallet_name = "" reset() onClickedBack() } diff --git a/atomic_qt_design/qml/Screens/NewUser.qml b/atomic_qt_design/qml/Screens/NewUser.qml index 6c687e351b..a97d517b50 100644 --- a/atomic_qt_design/qml/Screens/NewUser.qml +++ b/atomic_qt_design/qml/Screens/NewUser.qml @@ -77,6 +77,7 @@ SetupPage { function onClickedCreate(password, generated_seed, wallet_name) { if(API.get().create(password, generated_seed, wallet_name)) { console.log("Success: Create wallet") + selected_wallet_name = wallet_name postCreateSuccess() return true } diff --git a/atomic_qt_design/qml/Screens/RecoverSeed.qml b/atomic_qt_design/qml/Screens/RecoverSeed.qml index 87892ae85c..6648ce0d32 100644 --- a/atomic_qt_design/qml/Screens/RecoverSeed.qml +++ b/atomic_qt_design/qml/Screens/RecoverSeed.qml @@ -19,6 +19,7 @@ SetupPage { function onClickedConfirm(password, seed, wallet_name) { if(API.get().create(password, seed, wallet_name)) { console.log("Success: Recover seed") + selected_wallet_name = wallet_name postConfirmSuccess() return true } From 8a89df3e67c8de703d66087e0f110912f615f48f Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 29 Jul 2020 20:58:41 +0300 Subject: [PATCH 079/515] feat(gui): fix default wallet was saving after wallet creation --- atomic_qt_design/qml/App.qml | 2 +- atomic_qt_design/qml/Screens/Login.qml | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/App.qml b/atomic_qt_design/qml/App.qml index c1d5e2cb69..023c1396be 100644 --- a/atomic_qt_design/qml/App.qml +++ b/atomic_qt_design/qml/App.qml @@ -14,7 +14,7 @@ Rectangle { property string selected_wallet_name: "" function firstPage() { - return !API.get().first_run() && API.get().is_there_a_default_wallet() ? idx_login : idx_first_launch + return !API.get().first_run() && selected_wallet_name !== "" ? idx_login : idx_first_launch } function cleanApp() { diff --git a/atomic_qt_design/qml/Screens/Login.qml b/atomic_qt_design/qml/Screens/Login.qml index cf277b8dfa..09edf59f53 100644 --- a/atomic_qt_design/qml/Screens/Login.qml +++ b/atomic_qt_design/qml/Screens/Login.qml @@ -72,7 +72,6 @@ SetupPage { text: API.get().empty_string + (qsTr("Back")) Layout.fillWidth: true onClicked: { - selected_wallet_name = "" reset() onClickedBack() } From 8397ecf899e1b85bff6a78ff49b7836f4e0feb0d Mon Sep 17 00:00:00 2001 From: milerius Date: Wed, 29 Jul 2020 20:14:45 +0200 Subject: [PATCH 080/515] feat(notification): starting notification feature --- CMakeLists.txt | 1 + src/atomic.dex.notification.manager.cpp | 22 ++++++++++++++++++++++ src/atomic.dex.notification.manager.hpp | 22 ++++++++++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 src/atomic.dex.notification.manager.cpp create mode 100644 src/atomic.dex.notification.manager.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b08a40cf9d..0b38de5cac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -154,6 +154,7 @@ target_sources(atomic_qt_shared_deps INTERFACE ${CMAKE_SOURCE_DIR}/src/atomic.dex.wallet.config.cpp ${CMAKE_SOURCE_DIR}/src/atomic.dex.security.cpp ${CMAKE_SOURCE_DIR}/src/atomic.dex.update.service.cpp + ${CMAKE_SOURCE_DIR}/src/atomic.dex.notification.manager.cpp ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.orders.model.cpp ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.orders.proxy.model.cpp ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.candlestick.charts.model.cpp diff --git a/src/atomic.dex.notification.manager.cpp b/src/atomic.dex.notification.manager.cpp new file mode 100644 index 0000000000..2c4cf8fc49 --- /dev/null +++ b/src/atomic.dex.notification.manager.cpp @@ -0,0 +1,22 @@ +/****************************************************************************** + * Copyright © 2013-2019 The Komodo Platform Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * Komodo Platform software, including this file may be copied, modified, * + * propagated or distributed except according to the terms contained in the * + * LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + +#include "atomic.dex.notification.manager.hpp" + +namespace atomic_dex +{ + +} \ No newline at end of file diff --git a/src/atomic.dex.notification.manager.hpp b/src/atomic.dex.notification.manager.hpp new file mode 100644 index 0000000000..083459185d --- /dev/null +++ b/src/atomic.dex.notification.manager.hpp @@ -0,0 +1,22 @@ +/****************************************************************************** + * Copyright © 2013-2019 The Komodo Platform Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * Komodo Platform software, including this file may be copied, modified, * + * propagated or distributed except according to the terms contained in the * + * LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + +#pragma once + +namespace atomic_dex +{ + +} \ No newline at end of file From d74be0400820abb2259402977eb225d79135cb2b Mon Sep 17 00:00:00 2001 From: milerius Date: Wed, 29 Jul 2020 20:26:27 +0200 Subject: [PATCH 081/515] feat(notification): add notification manager skeleton --- src/atomic.dex.app.cpp | 15 ++++++++++++++- src/atomic.dex.app.hpp | 6 ++++++ src/atomic.dex.notification.manager.cpp | 22 +++++++++++++++++++++- src/atomic.dex.notification.manager.hpp | 21 ++++++++++++++++++++- 4 files changed, 61 insertions(+), 3 deletions(-) diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index 5c08790a48..afa93c7d6a 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -422,7 +422,8 @@ namespace atomic_dex {"update_needed", false}, {"changelog", ""}, {"current_version", ""}, {"download_url", ""}, {"new_version", ""}, {"rpc_code", 0}, {"status", ""}}), m_coin_info(new current_coin_info(dispatcher_, this)), m_addressbook(new addressbook_model(this->m_wallet_manager, this)), m_portfolio(new portfolio_model(this->system_manager_, this->m_config, this)), m_orders(new orders_model(this->system_manager_, this)), - m_candlestick_chart_ohlc(new candlestick_charts_model(this->system_manager_, this)), m_orderbook(new qt_orderbook_wrapper(this->system_manager_, this)) + m_candlestick_chart_ohlc(new candlestick_charts_model(this->system_manager_, this)), m_orderbook(new qt_orderbook_wrapper(this->system_manager_, this)), + m_notification_manager(new notification_manager(this->dispatcher_, this)) { get_dispatcher().sink().connect<&application::on_refresh_update_status_event>(*this); //! MM2 system need to be created before the GUI and give the instance to the gui @@ -851,6 +852,7 @@ namespace atomic_dex system_manager_.mark_system(); //! Disconnect signals + this->m_notification_manager->disconnect_signals(); get_dispatcher().sink().disconnect<&application::on_ticker_balance_updated_event>(*this); get_dispatcher().sink().disconnect<&application::on_change_ticker_event>(*this); get_dispatcher().sink().disconnect<&application::on_enabled_coins_event>(*this); @@ -875,6 +877,7 @@ namespace atomic_dex application::connect_signals() { spdlog::debug("{} l{}", __FUNCTION__, __LINE__); + this->m_notification_manager->connect_signals(); get_dispatcher().sink().connect<&application::on_ticker_balance_updated_event>(*this); get_dispatcher().sink().connect<&application::on_change_ticker_event>(*this); get_dispatcher().sink().connect<&application::on_enabled_coins_event>(*this); @@ -1481,4 +1484,14 @@ namespace atomic_dex this->m_orderbook_need_a_reset = evt.is_a_reset; } } +} // namespace atomic_dex + +//! Notification +namespace atomic_dex +{ + notification_manager* + application::get_notification_manager() const noexcept + { + return m_notification_manager; + } } // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.app.hpp b/src/atomic.dex.app.hpp index f1da9586bd..73da7c407f 100644 --- a/src/atomic.dex.app.hpp +++ b/src/atomic.dex.app.hpp @@ -31,6 +31,7 @@ //! Project Headers #include "atomic.dex.cfg.hpp" #include "atomic.dex.mm2.hpp" +#include "atomic.dex.notification.manager.hpp" #include "atomic.dex.provider.coinpaprika.hpp" #include "atomic.dex.qt.addressbook.model.hpp" #include "atomic.dex.qt.bindings.hpp" @@ -62,6 +63,7 @@ namespace atomic_dex Q_PROPERTY(candlestick_charts_model* candlestick_charts_mdl READ get_candlestick_charts NOTIFY candlestickChartsChanged) Q_PROPERTY(QVariant update_status READ get_update_status NOTIFY updateStatusChanged) Q_PROPERTY(portfolio_model* portfolio_mdl READ get_portfolio NOTIFY portfolioChanged) + Q_PROPERTY(notification_manager* notification_mgr READ get_notification_manager) Q_PROPERTY(QString current_currency READ get_current_currency WRITE set_current_currency NOTIFY on_currency_changed) Q_PROPERTY(QString current_fiat READ get_current_fiat WRITE set_current_fiat NOTIFY on_fiat_changed) Q_PROPERTY(QString lang READ get_current_lang WRITE set_current_lang NOTIFY on_lang_changed) @@ -125,6 +127,7 @@ namespace atomic_dex addressbook_model* get_addressbook() const noexcept; portfolio_model* get_portfolio() const noexcept; orders_model* get_orders() const noexcept; + notification_manager* get_notification_manager() const noexcept;; candlestick_charts_model* get_candlestick_charts() const noexcept; qt_orderbook_wrapper* get_orderbook_wrapper() const noexcept; QVariantList get_enabled_coins() const noexcept; @@ -294,6 +297,9 @@ namespace atomic_dex qt_orderbook_wrapper* m_orderbook; std::atomic_bool m_orderbook_need_a_reset{false}; + //! Notification + notification_manager* m_notification_manager; + std::atomic_bool m_about_to_exit_app{false}; }; } // namespace atomic_dex diff --git a/src/atomic.dex.notification.manager.cpp b/src/atomic.dex.notification.manager.cpp index 2c4cf8fc49..dc622cd807 100644 --- a/src/atomic.dex.notification.manager.cpp +++ b/src/atomic.dex.notification.manager.cpp @@ -18,5 +18,25 @@ namespace atomic_dex { + notification_manager::notification_manager(entt::dispatcher& dispatcher, QObject* parent) noexcept : QObject(parent), m_dispatcher(dispatcher) + { + spdlog::trace("{} l{} f[{}]", __FUNCTION__, __LINE__, fs::path(__FILE__).filename().string()); + spdlog::trace("notification manager created"); + } -} \ No newline at end of file + notification_manager::~notification_manager() noexcept + { + spdlog::trace("{} l{} f[{}]", __FUNCTION__, __LINE__, fs::path(__FILE__).filename().string()); + spdlog::trace("notification manager destroyed"); + } + + void + atomic_dex::notification_manager::connect_signals() noexcept + { + } + + void + atomic_dex::notification_manager::disconnect_signals() noexcept + { + } +} // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.notification.manager.hpp b/src/atomic.dex.notification.manager.hpp index 083459185d..5eca53f46e 100644 --- a/src/atomic.dex.notification.manager.hpp +++ b/src/atomic.dex.notification.manager.hpp @@ -16,7 +16,26 @@ #pragma once +//! QT Include +#include + +//! PCH Header +#include "atomic.dex.pch.hpp" + namespace atomic_dex { + class notification_manager final : public QObject + { + Q_OBJECT + public: + notification_manager(entt::dispatcher& dispatcher, QObject* parent = nullptr) noexcept; + ~notification_manager() noexcept final; + + //! Public API + void connect_signals() noexcept; + void disconnect_signals() noexcept; -} \ No newline at end of file + private: + entt::dispatcher& m_dispatcher; + }; +} // namespace atomic_dex \ No newline at end of file From 780876f94989e084a1a1d11b2131648140c753a3 Mon Sep 17 00:00:00 2001 From: milerius Date: Wed, 29 Jul 2020 20:28:51 +0200 Subject: [PATCH 082/515] feat(notification): add updateSwapStatus signals --- src/atomic.dex.notification.manager.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/atomic.dex.notification.manager.hpp b/src/atomic.dex.notification.manager.hpp index 5eca53f46e..2d888ebfe6 100644 --- a/src/atomic.dex.notification.manager.hpp +++ b/src/atomic.dex.notification.manager.hpp @@ -35,6 +35,9 @@ namespace atomic_dex void connect_signals() noexcept; void disconnect_signals() noexcept; + signals: + void updateSwapStatus(QString old_swap_status, QString new_swap_status, QString swap_uuid); + private: entt::dispatcher& m_dispatcher; }; From 9f98466e961c2018cedd90410fd838ecbaa6acef Mon Sep 17 00:00:00 2001 From: milerius Date: Wed, 29 Jul 2020 21:12:49 +0200 Subject: [PATCH 083/515] feat(notification): add backend for notifications --- CMakeLists.txt | 3 ++- src/atomic.dex.app.cpp | 3 ++- src/atomic.dex.events.hpp | 7 +++++ src/atomic.dex.notification.manager.cpp | 12 +++++++-- src/atomic.dex.notification.manager.hpp | 6 +++++ src/atomic.dex.qt.orders.model.cpp | 34 +++++++++++++++++-------- src/atomic.dex.qt.orders.model.hpp | 3 ++- 7 files changed, 52 insertions(+), 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0b38de5cac..a4ac60306b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -98,7 +98,7 @@ find_package(doctest CONFIG REQUIRED) find_package(folly CONFIG REQUIRED) find_package(spdlog CONFIG REQUIRED) find_package(Boost REQUIRED COMPONENTS filesystem random) -find_package(Qt5 COMPONENTS Core Quick LinguistTools Svg Charts REQUIRED) +find_package(Qt5 COMPONENTS Core Quick LinguistTools Svg Charts Widgets REQUIRED) find_package(unofficial-sodium CONFIG REQUIRED) find_library(unofficial-bitcoin-external bitcoin) find_path(unofficial-btc-headers bitcoin/bitcoin.hpp) @@ -186,6 +186,7 @@ target_link_libraries(atomic_qt_shared_deps Qt5::Quick Qt5::Svg Qt5::Charts + Qt5::Widgets qzxing antara::world Boost::filesystem diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index afa93c7d6a..97282e3665 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -421,7 +421,8 @@ namespace atomic_dex m_update_status(QJsonObject{ {"update_needed", false}, {"changelog", ""}, {"current_version", ""}, {"download_url", ""}, {"new_version", ""}, {"rpc_code", 0}, {"status", ""}}), m_coin_info(new current_coin_info(dispatcher_, this)), m_addressbook(new addressbook_model(this->m_wallet_manager, this)), - m_portfolio(new portfolio_model(this->system_manager_, this->m_config, this)), m_orders(new orders_model(this->system_manager_, this)), + m_portfolio(new portfolio_model(this->system_manager_, this->m_config, this)), + m_orders(new orders_model(this->system_manager_, this->dispatcher_, this)), m_candlestick_chart_ohlc(new candlestick_charts_model(this->system_manager_, this)), m_orderbook(new qt_orderbook_wrapper(this->system_manager_, this)), m_notification_manager(new notification_manager(this->dispatcher_, this)) { diff --git a/src/atomic.dex.events.hpp b/src/atomic.dex.events.hpp index 6767099c71..cc803a6eb3 100644 --- a/src/atomic.dex.events.hpp +++ b/src/atomic.dex.events.hpp @@ -34,6 +34,13 @@ namespace atomic_dex using process_swaps_finished = entt::tag<"gui_process_swaps_finished"_hs>; // using process_orderbook_finished = entt::tag<"gui_process_orderbook_finished"_hs>; + struct swap_status_notification + { + std::string uuid; + std::string prev_status; + std::string new_status; + }; + struct process_orderbook_finished { bool is_a_reset; diff --git a/src/atomic.dex.notification.manager.cpp b/src/atomic.dex.notification.manager.cpp index dc622cd807..5577e0621e 100644 --- a/src/atomic.dex.notification.manager.cpp +++ b/src/atomic.dex.notification.manager.cpp @@ -31,12 +31,20 @@ namespace atomic_dex } void - atomic_dex::notification_manager::connect_signals() noexcept + notification_manager::on_swap_status_notification(const atomic_dex::swap_status_notification& evt) { + emit updateSwapStatus(QString::fromStdString(evt.prev_status), QString::fromStdString(evt.new_status), QString::fromStdString(evt.uuid)); } void - atomic_dex::notification_manager::disconnect_signals() noexcept + notification_manager::connect_signals() noexcept { + m_dispatcher.sink().connect<¬ification_manager::on_swap_status_notification>(*this); + } + + void + notification_manager::disconnect_signals() noexcept + { + m_dispatcher.sink().disconnect<¬ification_manager::on_swap_status_notification>(*this); } } // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.notification.manager.hpp b/src/atomic.dex.notification.manager.hpp index 2d888ebfe6..ae0d73501f 100644 --- a/src/atomic.dex.notification.manager.hpp +++ b/src/atomic.dex.notification.manager.hpp @@ -22,6 +22,9 @@ //! PCH Header #include "atomic.dex.pch.hpp" +//! Project Headers +#include "atomic.dex.events.hpp" + namespace atomic_dex { class notification_manager final : public QObject @@ -35,6 +38,9 @@ namespace atomic_dex void connect_signals() noexcept; void disconnect_signals() noexcept; + //! Callbacks + void on_swap_status_notification(const swap_status_notification& evt); + signals: void updateSwapStatus(QString old_swap_status, QString new_swap_status, QString swap_uuid); diff --git a/src/atomic.dex.qt.orders.model.cpp b/src/atomic.dex.qt.orders.model.cpp index 78207add25..f2ead00d35 100644 --- a/src/atomic.dex.qt.orders.model.cpp +++ b/src/atomic.dex.qt.orders.model.cpp @@ -21,14 +21,16 @@ //! Utils namespace { - template - void - update_value(int role, const TValue& value, const QModelIndex& idx, TModel& model) + template + auto + update_value(int role, const QVariant& value, const QModelIndex& idx, TModel& model) { - if (value != model.data(idx, role)) + if (auto prev_value = model.data(idx, role); value != prev_value) { model.setData(idx, value, role); + return std::make_tuple(prev_value, value, true); } + return std::make_tuple(value, value, false); } std::pair @@ -55,8 +57,8 @@ namespace namespace atomic_dex { - orders_model::orders_model(ag::ecs::system_manager& system_manager, QObject* parent) noexcept : - QAbstractListModel(parent), m_system_manager(system_manager), m_model_proxy(new orders_proxy_model(this)) + orders_model::orders_model(ag::ecs::system_manager& system_manager, entt::dispatcher& dispatcher, QObject* parent) noexcept : + QAbstractListModel(parent), m_system_manager(system_manager), m_dispatcher(dispatcher), m_model_proxy(new orders_proxy_model(this)) { spdlog::trace("{} l{} f[{}]", __FUNCTION__, __LINE__, fs::path(__FILE__).filename().string()); spdlog::trace("orders model created"); @@ -313,7 +315,8 @@ namespace atomic_dex data.order_error_state = error.first; data.order_error_message = error.second; } - if (this->m_swaps_id_registry.find(contents.uuid) == m_swaps_id_registry.end()) { + if (this->m_swaps_id_registry.find(contents.uuid) == m_swaps_id_registry.end()) + { this->m_swaps_id_registry.emplace(contents.uuid); } this->m_model_data.push_back(std::move(data)); @@ -329,7 +332,12 @@ namespace atomic_dex const QModelIndex& idx = res.at(0); bool is_maker = boost::algorithm::to_lower_copy(contents.type) == "maker"; update_value(OrdersRoles::IsRecoverableRole, contents.funds_recoverable, idx, *this); - update_value(OrdersRoles::OrderStatusRole, determine_order_status_from_last_event(contents), idx, *this); + auto&& [prev_value, new_value, is_change] = + update_value(OrdersRoles::OrderStatusRole, determine_order_status_from_last_event(contents), idx, *this); + if (is_change) + { + this->m_dispatcher.trigger(contents.uuid, prev_value.toString().toStdString(), new_value.toString().toStdString()); + } update_value( OrdersRoles::UnixTimestampRole, not contents.events.empty() ? contents.events.back().at("timestamp").get() : 0, idx, *this); update_value( @@ -341,9 +349,13 @@ namespace atomic_dex update_value(OrdersRoles::OrderErrorStateRole, state, idx, *this); update_value(OrdersRoles::OrderErrorMessageRole, msg, idx, *this); emit lengthChanged(); - } else { - bool is_maker = boost::algorithm::to_lower_copy(contents.type) == "maker"; - spdlog::error("swap with id {} and ticker: {}, not found in the model, cannot update, forcing an initialization instead", contents.uuid, is_maker ? contents.maker_coin : contents.taker_coin); + } + else + { + bool is_maker = boost::algorithm::to_lower_copy(contents.type) == "maker"; + spdlog::error( + "swap with id {} and ticker: {}, not found in the model, cannot update, forcing an initialization instead", contents.uuid, + is_maker ? contents.maker_coin : contents.taker_coin); initialize_swap(contents); } } diff --git a/src/atomic.dex.qt.orders.model.hpp b/src/atomic.dex.qt.orders.model.hpp index 23ae16eec2..4a85c190eb 100644 --- a/src/atomic.dex.qt.orders.model.hpp +++ b/src/atomic.dex.qt.orders.model.hpp @@ -60,7 +60,7 @@ namespace atomic_dex }; - orders_model(ag::ecs::system_manager& system_manager, QObject* parent = nullptr) noexcept; + orders_model(ag::ecs::system_manager& system_manager, entt::dispatcher& dispatcher, QObject* parent = nullptr) noexcept; ~orders_model() noexcept final; int rowCount(const QModelIndex& parent) const final; QVariant data(const QModelIndex& index, int role) const final; @@ -82,6 +82,7 @@ namespace atomic_dex private: ag::ecs::system_manager& m_system_manager; + entt::dispatcher& m_dispatcher; using t_orders_datas = QVector; using t_orders_id_registry = std::unordered_set; From 2f085837e56b4c00a5f03dd022002f3e682ce31c Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 29 Jul 2020 22:17:11 +0300 Subject: [PATCH 084/515] feat(gui): add NotificationsPanel --- .../qml/Dashboard/NotificationsPanel.qml | 53 +++++++++++++++++++ atomic_qt_design/qml/Screens/Dashboard.qml | 8 +++ qml.qrc | 1 + 3 files changed, 62 insertions(+) create mode 100644 atomic_qt_design/qml/Dashboard/NotificationsPanel.qml diff --git a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml new file mode 100644 index 0000000000..448b01300d --- /dev/null +++ b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml @@ -0,0 +1,53 @@ +import QtQuick 2.12 +import QtQuick.Layouts 1.12 +import QtQuick.Controls 2.12 +import Qt.labs.platform 1.0 + +import "../Constants" +import "../Components" + +FloatingBackground { + id: root + + SystemTrayIcon { + id: tray + visible: true + iconSource: General.coinIcon("KMD") + onMessageClicked: console.log("Message clicked") + + tooltip: qsTr("AtomicDEX Pro") + } + + ColumnLayout { + anchors.fill: parent + anchors.margins: 40 + DefaultText { + text_value: API.get().empty_string + (qsTr("Notifications")) + Layout.alignment: Qt.AlignLeft | Qt.AlignTop + font.pixelSize: Style.textSize3 + } + + HorizontalLine { + Layout.alignment: Qt.AlignTop + Layout.fillWidth: true + } + + DefaultButton { + text: API.get().empty_string + (qsTr("Pop Notification")) + Layout.alignment: Qt.AlignTop + onClicked: { + console.log("System tray is " + (tray.available ? "available" : "not available")) + console.log("Messages are " + (tray.supportsMessages ? "supported" : "not supported")) + tray.showMessage("You received 31 BTC", "Click here to hear more lies.", 1) + } + } + } +} + + + +/*##^## +Designer { + D{i:0;autoSize:true;height:480;width:640} +} +##^##*/ diff --git a/atomic_qt_design/qml/Screens/Dashboard.qml b/atomic_qt_design/qml/Screens/Dashboard.qml index 1151ca8bf9..e5ea2a1ed1 100644 --- a/atomic_qt_design/qml/Screens/Dashboard.qml +++ b/atomic_qt_design/qml/Screens/Dashboard.qml @@ -6,6 +6,7 @@ import QtGraphicalEffects 1.0 import "../Components" import "../Constants" +import "../Dashboard" import "../Portfolio" import "../Wallet" import "../Exchange" @@ -171,6 +172,13 @@ Item { } } } + + NotificationsPanel { + width: 300 + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + } } diff --git a/qml.qrc b/qml.qrc index 1dbb7230de..5ae0abe300 100644 --- a/qml.qrc +++ b/qml.qrc @@ -174,6 +174,7 @@ atomic_qt_design/qml/Components/TextAreaWithTitle.qml atomic_qt_design/qml/Components/ModalHeader.qml atomic_qt_design/qml/Components/CexInfoTrigger.qml + atomic_qt_design/qml/Dashboard/NotificationsPanel.qml atomic_qt_design/qml/Portfolio/Portfolio.qml atomic_qt_design/qml/Wallet/Wallet.qml atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml From f9d0a2cea53a0c86c7e1a82540723f763be95faf Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 29 Jul 2020 22:33:17 +0300 Subject: [PATCH 085/515] feat(gui): add onSwapStatusUpdated --- .../qml/Dashboard/NotificationsPanel.qml | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml index 448b01300d..5104812b52 100644 --- a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml +++ b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml @@ -9,11 +9,31 @@ import "../Components" FloatingBackground { id: root + visible: false + + // Events + function onSwapStatusUpdated(old_swap_status, new_swap_status, swap_uuid) { + displayMessage(qsTr("Swap status updated"), old_swap_status + " " + General.right_arrow_icon + " " + new_swap_status) + } + + + // System + Component.onCompleted: { + API.get().notification_mgr.updateSwapStatus.connect(onSwapStatusUpdated) + } + + function displayMessage(title, message) { + tray.showMessage(title, message) + } + SystemTrayIcon { id: tray visible: true iconSource: General.coinIcon("KMD") - onMessageClicked: console.log("Message clicked") + onMessageClicked: { + console.log("Message clicked") + root.visible = true + } tooltip: qsTr("AtomicDEX Pro") } @@ -38,7 +58,8 @@ FloatingBackground { onClicked: { console.log("System tray is " + (tray.available ? "available" : "not available")) console.log("Messages are " + (tray.supportsMessages ? "supported" : "not supported")) - tray.showMessage("You received 31 BTC", "Click here to hear more lies.", 1) + //displayMessage("You received 31 BTC", "Click here to hear more lies.") + onSwapStatusUpdated("Ongoing", "Finished", "123456") } } } From b528783ad4dba743d1ed2afb9bfb4e82dd6d1c50 Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 29 Jul 2020 22:46:20 +0300 Subject: [PATCH 086/515] feat(gui): open the app at icon click --- atomic_qt_design/qml/Dashboard/NotificationsPanel.qml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml index 5104812b52..bcd517afcf 100644 --- a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml +++ b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml @@ -36,6 +36,12 @@ FloatingBackground { } tooltip: qsTr("AtomicDEX Pro") + + onActivated: { + window.show() + window.raise() + window.requestActivate() + } } ColumnLayout { From 7057d968c332da83e2ede739c620c68935c3555c Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 29 Jul 2020 22:46:31 +0300 Subject: [PATCH 087/515] feat(gui): close button --- atomic_qt_design/qml/Dashboard/NotificationsPanel.qml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml index bcd517afcf..b5506cf0c8 100644 --- a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml +++ b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml @@ -50,7 +50,7 @@ FloatingBackground { DefaultText { text_value: API.get().empty_string + (qsTr("Notifications")) Layout.alignment: Qt.AlignLeft | Qt.AlignTop - font.pixelSize: Style.textSize3 + font.pixelSize: Style.textSize2 } HorizontalLine { @@ -68,6 +68,12 @@ FloatingBackground { onSwapStatusUpdated("Ongoing", "Finished", "123456") } } + + DefaultButton { + text: API.get().empty_string + (qsTr("Close")) + Layout.alignment: Qt.AlignRight + onClicked: root.visible = false + } } } From a0014be1b65018e85e48ef45dcd608375113b3d2 Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 29 Jul 2020 22:46:59 +0300 Subject: [PATCH 088/515] feat(gui): reset notifications panel at login --- atomic_qt_design/qml/Dashboard/NotificationsPanel.qml | 4 ++++ atomic_qt_design/qml/Screens/Dashboard.qml | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml index b5506cf0c8..1733b626a5 100644 --- a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml +++ b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml @@ -9,6 +9,10 @@ import "../Components" FloatingBackground { id: root + function reset() { + visible = false + } + visible: false // Events diff --git a/atomic_qt_design/qml/Screens/Dashboard.qml b/atomic_qt_design/qml/Screens/Dashboard.qml index e5ea2a1ed1..2cc29abfac 100644 --- a/atomic_qt_design/qml/Screens/Dashboard.qml +++ b/atomic_qt_design/qml/Screens/Dashboard.qml @@ -39,6 +39,7 @@ Item { news.reset() dapps.reset() settings.reset() + notifications_panel.reset() } function inCurrentPage() { @@ -174,10 +175,11 @@ Item { } NotificationsPanel { + id: notifications_panel width: 300 + height: 600 anchors.right: parent.right anchors.top: parent.top - anchors.bottom: parent.bottom } } From d01de9725fa5d77c26c964042e9641d06d79ff21 Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 29 Jul 2020 22:50:46 +0300 Subject: [PATCH 089/515] feat(gui): add notifications button to the sidebar --- atomic_qt_design/qml/Sidebar/Sidebar.qml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/atomic_qt_design/qml/Sidebar/Sidebar.qml b/atomic_qt_design/qml/Sidebar/Sidebar.qml index 6175874e98..30510f69b1 100644 --- a/atomic_qt_design/qml/Sidebar/Sidebar.qml +++ b/atomic_qt_design/qml/Sidebar/Sidebar.qml @@ -149,6 +149,15 @@ Item { anchors.verticalCenter: parent.verticalCenter } + DefaultButton { + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: sidebar_bottom.top + anchors.bottomMargin: 25 + text: "🔔" + minWidth: height + onClicked: notifications_panel.visible = !notifications_panel.visible + } + SidebarBottom { id: sidebar_bottom width: parent.width From c0aad6efae0c9ca0e921de60e14b730d8475c6f7 Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 29 Jul 2020 22:57:19 +0300 Subject: [PATCH 090/515] feat(gui): show app on message click --- .../qml/Dashboard/NotificationsPanel.qml | 20 +++++++++++++------ atomic_qt_design/qml/Screens/Dashboard.qml | 2 ++ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml index 1733b626a5..e440b4b15d 100644 --- a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml +++ b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml @@ -13,8 +13,20 @@ FloatingBackground { visible = false } + function showApp() { + window.show() + window.raise() + window.requestActivate() + } + visible: false + MouseArea { + anchors.fill: parent + preventStealing: true + hoverEnabled: true + } + // Events function onSwapStatusUpdated(old_swap_status, new_swap_status, swap_uuid) { displayMessage(qsTr("Swap status updated"), old_swap_status + " " + General.right_arrow_icon + " " + new_swap_status) @@ -35,17 +47,13 @@ FloatingBackground { visible: true iconSource: General.coinIcon("KMD") onMessageClicked: { - console.log("Message clicked") root.visible = true + showApp() } tooltip: qsTr("AtomicDEX Pro") - onActivated: { - window.show() - window.raise() - window.requestActivate() - } + onActivated: showApp() } ColumnLayout { diff --git a/atomic_qt_design/qml/Screens/Dashboard.qml b/atomic_qt_design/qml/Screens/Dashboard.qml index 2cc29abfac..7028275fdf 100644 --- a/atomic_qt_design/qml/Screens/Dashboard.qml +++ b/atomic_qt_design/qml/Screens/Dashboard.qml @@ -180,6 +180,8 @@ Item { height: 600 anchors.right: parent.right anchors.top: parent.top + anchors.rightMargin: 40 + anchors.topMargin: anchors.rightMargin } } From be33d6f1f2b426c8a4b90f24131833b8cb0ccda0 Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 29 Jul 2020 22:57:30 +0300 Subject: [PATCH 091/515] feat(gui): cleanup --- atomic_qt_design/qml/Dashboard/NotificationsPanel.qml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml index e440b4b15d..f72436160e 100644 --- a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml +++ b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml @@ -29,6 +29,7 @@ FloatingBackground { // Events function onSwapStatusUpdated(old_swap_status, new_swap_status, swap_uuid) { + // TODO: Add qsTr texts for statuses displayMessage(qsTr("Swap status updated"), old_swap_status + " " + General.right_arrow_icon + " " + new_swap_status) } @@ -74,10 +75,7 @@ FloatingBackground { text: API.get().empty_string + (qsTr("Pop Notification")) Layout.alignment: Qt.AlignTop onClicked: { - console.log("System tray is " + (tray.available ? "available" : "not available")) - console.log("Messages are " + (tray.supportsMessages ? "supported" : "not supported")) - //displayMessage("You received 31 BTC", "Click here to hear more lies.") - onSwapStatusUpdated("Ongoing", "Finished", "123456") + onSwapStatusUpdated("ongoing", "finished", "123456") } } From e4327a667ca13ca751ce4e18e3045488718d40d0 Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 29 Jul 2020 23:06:23 +0300 Subject: [PATCH 092/515] feat(gui): move notifications panel to bottom left --- atomic_qt_design/qml/Screens/Dashboard.qml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/atomic_qt_design/qml/Screens/Dashboard.qml b/atomic_qt_design/qml/Screens/Dashboard.qml index 7028275fdf..e8a47c6c57 100644 --- a/atomic_qt_design/qml/Screens/Dashboard.qml +++ b/atomic_qt_design/qml/Screens/Dashboard.qml @@ -178,10 +178,10 @@ Item { id: notifications_panel width: 300 height: 600 - anchors.right: parent.right - anchors.top: parent.top - anchors.rightMargin: 40 - anchors.topMargin: anchors.rightMargin + anchors.left: sidebar.right + anchors.bottom: parent.bottom + anchors.leftMargin: 20 + anchors.bottomMargin: anchors.leftMargin } } From d61f92deec193c715d26a00e01f3bdd9b7276f22 Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 29 Jul 2020 23:20:49 +0300 Subject: [PATCH 093/515] feat(gui): fix window size was changing on icon click --- .../qml/Dashboard/NotificationsPanel.qml | 3 +- atomic_qt_design/qml/Screens/Dashboard.qml | 30 +++++++++---------- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml index f72436160e..26497d05a9 100644 --- a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml +++ b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml @@ -14,7 +14,6 @@ FloatingBackground { } function showApp() { - window.show() window.raise() window.requestActivate() } @@ -81,7 +80,7 @@ FloatingBackground { DefaultButton { text: API.get().empty_string + (qsTr("Close")) - Layout.alignment: Qt.AlignRight + Layout.alignment: Qt.AlignBottom onClicked: root.visible = false } } diff --git a/atomic_qt_design/qml/Screens/Dashboard.qml b/atomic_qt_design/qml/Screens/Dashboard.qml index e8a47c6c57..45db8b99f4 100644 --- a/atomic_qt_design/qml/Screens/Dashboard.qml +++ b/atomic_qt_design/qml/Screens/Dashboard.qml @@ -80,12 +80,6 @@ Item { repeat: true onTriggered: General.enableEthIfNeeded() } - - // Sidebar, left side - Sidebar { - id: sidebar - } - // Right side Rectangle { color: Style.colorTheme8 @@ -137,6 +131,20 @@ Item { } } + NotificationsPanel { + id: notifications_panel + width: 300 + height: 600 + anchors.left: sidebar.right + anchors.bottom: parent.bottom + anchors.bottomMargin: -40 + } + + // Sidebar, left side + Sidebar { + id: sidebar + } + DropShadow { anchors.fill: sidebar source: sidebar @@ -173,16 +181,6 @@ Item { } } } - - NotificationsPanel { - id: notifications_panel - width: 300 - height: 600 - anchors.left: sidebar.right - anchors.bottom: parent.bottom - anchors.leftMargin: 20 - anchors.bottomMargin: anchors.leftMargin - } } From 13fb58ae727b8086b2f54fc723e96d6d156d8a91 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Thu, 30 Jul 2020 07:33:55 +0200 Subject: [PATCH 094/515] feat(notification): add notification for a swap insertion Signed-off-by: romanszterg --- src/atomic.dex.qt.orders.model.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/atomic.dex.qt.orders.model.cpp b/src/atomic.dex.qt.orders.model.cpp index f2ead00d35..6c3cd90d28 100644 --- a/src/atomic.dex.qt.orders.model.cpp +++ b/src/atomic.dex.qt.orders.model.cpp @@ -315,6 +315,11 @@ namespace atomic_dex data.order_error_state = error.first; data.order_error_message = error.second; } + if (data.order_status == "matched") + { + using namespace std::string_literals; + this->m_dispatcher.trigger(data.order_id.toStdString(), "matching"s, "matched"s); + } if (this->m_swaps_id_registry.find(contents.uuid) == m_swaps_id_registry.end()) { this->m_swaps_id_registry.emplace(contents.uuid); From 577212772f8017f6cc72d88aa8e904edcbdf5d37 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Thu, 30 Jul 2020 09:36:19 +0200 Subject: [PATCH 095/515] feat(buy): update buy rpc to use price denom and price numer from orderbook Signed-off-by: romanszterg --- src/atomic.dex.app.cpp | 21 +++++++++++--- src/atomic.dex.app.hpp | 6 ++-- src/atomic.dex.mm2.api.cpp | 58 +++++++++++++++++++++++--------------- src/atomic.dex.mm2.api.hpp | 3 ++ 4 files changed, 59 insertions(+), 29 deletions(-) diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index 5c08790a48..9b6cd91b0c 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -653,8 +653,10 @@ namespace atomic_dex } } - bool - application::place_buy_order(const QString& base, const QString& rel, const QString& price, const QString& volume) + QString + application::place_buy_order( + const QString& base, const QString& rel, const QString& price, const QString& volume, bool is_created_order, const QString& price_denom, + const QString& price_numer) { t_float_50 price_f; t_float_50 amount_f; @@ -664,11 +666,22 @@ namespace atomic_dex amount_f.assign(volume.toStdString()); total_amount = price_f * amount_f; - t_buy_request req{.base = base.toStdString(), .rel = rel.toStdString(), .price = price.toStdString(), .volume = volume.toStdString()}; + t_buy_request req{ + .base = base.toStdString(), + .rel = rel.toStdString(), + .price = price.toStdString(), + .volume = volume.toStdString(), + .is_created_order = is_created_order, + .price_denom = price_denom.toStdString(), + .price_numer = price_numer.toStdString()}; std::error_code ec; auto answer = get_mm2().place_buy_order(std::move(req), total_amount, ec); - return !answer.error.has_value(); + if (answer.error.has_value()) + { + return QString::fromStdString(answer.error.value()); + } + return ""; } QString diff --git a/src/atomic.dex.app.hpp b/src/atomic.dex.app.hpp index f1da9586bd..b538fdd596 100644 --- a/src/atomic.dex.app.hpp +++ b/src/atomic.dex.app.hpp @@ -201,10 +201,12 @@ namespace atomic_dex Q_INVOKABLE bool enable_coins(const QStringList& coins); Q_INVOKABLE QString get_balance(const QString& coin); Q_INVOKABLE static QString get_price_amount(const QString& base_amount, const QString& rel_amount); - Q_INVOKABLE bool place_buy_order(const QString& base, const QString& rel, const QString& price, const QString& volume); - Q_INVOKABLE QString place_sell_order( + Q_INVOKABLE QString place_buy_order( const QString& base, const QString& rel, const QString& price, const QString& volume, bool is_created_order, const QString& price_denom, const QString& price_numer); + Q_INVOKABLE QString place_sell_order( + const QString& base, const QString& rel, const QString& price, const QString& volume, bool is_created_order, const QString& price_denom, + const QString& price_numer); Q_INVOKABLE void set_current_orderbook(const QString& base, const QString& rel); Q_INVOKABLE bool do_i_have_enough_funds(const QString& ticker, const QString& amount) const; Q_INVOKABLE bool disable_coins(const QStringList& coins); diff --git a/src/atomic.dex.mm2.api.cpp b/src/atomic.dex.mm2.api.cpp index 9927270b59..97baf8ef57 100644 --- a/src/atomic.dex.mm2.api.cpp +++ b/src/atomic.dex.mm2.api.cpp @@ -440,29 +440,25 @@ namespace mm2::api sys_time tp{std::chrono::milliseconds{answer.timestamp}}; auto tp_zoned = date::make_zoned(current_zone(), tp); answer.human_timestamp = date::format("%Y-%m-%d %I:%M:%S", tp_zoned); - + t_float_50 result_asks_f("0"); - for (auto&& cur_asks : answer.asks) { - result_asks_f = result_asks_f + t_float_50(cur_asks.maxvolume); - } - + for (auto&& cur_asks: answer.asks) { result_asks_f = result_asks_f + t_float_50(cur_asks.maxvolume); } + answer.asks_total_volume = result_asks_f.str(); t_float_50 result_bids_f("0"); - for (auto&& cur_bids : answer.bids) { - result_bids_f = result_bids_f + t_float_50(cur_bids.maxvolume); - } - + for (auto&& cur_bids: answer.bids) { result_bids_f = result_bids_f + t_float_50(cur_bids.maxvolume); } + answer.bids_total_volume = result_bids_f.str(); - for (auto&& cur_asks : answer.asks) + for (auto&& cur_asks: answer.asks) { - t_float_50 percent_f = t_float_50(cur_asks.maxvolume) / result_asks_f; + t_float_50 percent_f = t_float_50(cur_asks.maxvolume) / result_asks_f; cur_asks.depth_percent = adjust_precision(percent_f.str()); } - for (auto&& cur_bids : answer.bids) + for (auto&& cur_bids: answer.bids) { - t_float_50 percent_f = t_float_50(cur_bids.maxvolume) / result_bids_f; + t_float_50 percent_f = t_float_50(cur_bids.maxvolume) / result_bids_f; cur_bids.depth_percent = adjust_precision(percent_f.str()); } } @@ -485,15 +481,6 @@ namespace mm2::api j["max"] = request.max; } - void - to_json(nlohmann::json& j, buy_request& request) - { - j["base"] = request.base; - j["price"] = request.price; - j["rel"] = request.rel; - j["volume"] = request.volume; - } - void from_json(const nlohmann::json& j, trading_order_contents& contents) { @@ -528,10 +515,35 @@ namespace mm2::api } void - to_json(nlohmann::json& j, const sell_request& request) + to_json(nlohmann::json& j, buy_request& request) { spdlog::debug("price: {}, volume: {}", request.price, request.volume); + j["base"] = request.base; + j["price"] = request.price; + j["rel"] = request.rel; + j["volume"] = request.volume; + + if (not request.is_created_order) + { + spdlog::info( + "The order is picked from the orderbook, setting price_numer and price_denom from it {}, {}", request.price_numer, request.price_denom); + //! From orderbook + nlohmann::json price_fraction_repr = nlohmann::json::object(); + price_fraction_repr["numer"] = request.price_numer; + price_fraction_repr["denom"] = request.price_denom; + j["price"] = price_fraction_repr; + } + else + { + spdlog::info("The order is not picked from orderbook we create it volume = {}, price = {}", request.volume, request.price); + } + } + + void + to_json(nlohmann::json& j, const sell_request& request) + { + spdlog::debug("price: {}, volume: {}", request.price, request.volume); j["base"] = request.base; j["rel"] = request.rel; diff --git a/src/atomic.dex.mm2.api.hpp b/src/atomic.dex.mm2.api.hpp index 5b2a0ae638..ac56ef8719 100644 --- a/src/atomic.dex.mm2.api.hpp +++ b/src/atomic.dex.mm2.api.hpp @@ -442,6 +442,9 @@ namespace mm2::api std::string rel; std::string price; std::string volume; + bool is_created_order; + std::string price_denom; + std::string price_numer; }; void to_json(nlohmann::json& j, const buy_request& request); From dce7dedcc0785add2337f0b7c86965d1f7e20b58 Mon Sep 17 00:00:00 2001 From: milerius Date: Thu, 30 Jul 2020 12:46:50 +0200 Subject: [PATCH 096/515] feat(internet_services): add basis backend for internet checking --- CMakeLists.txt | 1 + ...atomic.dex.qt.internet.checker.service.cpp | 74 +++++++++++++++++++ ...atomic.dex.qt.internet.checker.service.hpp | 65 ++++++++++++++++ 3 files changed, 140 insertions(+) create mode 100644 src/atomic.dex.qt.internet.checker.service.cpp create mode 100644 src/atomic.dex.qt.internet.checker.service.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b08a40cf9d..cd8aacf897 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -137,6 +137,7 @@ message(STATUS "${TS_FILES}") add_library(atomic_qt_shared_deps INTERFACE) target_sources(atomic_qt_shared_deps INTERFACE ${CMAKE_SOURCE_DIR}/src/atomic.dex.kill.cpp + ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.internet.checker.service.cpp ${CMAKE_SOURCE_DIR}/src/atomic.dex.app.cpp ${CMAKE_SOURCE_DIR}/src/atomic.dex.cfg.cpp ${CMAKE_SOURCE_DIR}/src/atomic.dex.mm2.cpp diff --git a/src/atomic.dex.qt.internet.checker.service.cpp b/src/atomic.dex.qt.internet.checker.service.cpp new file mode 100644 index 0000000000..cd9039affa --- /dev/null +++ b/src/atomic.dex.qt.internet.checker.service.cpp @@ -0,0 +1,74 @@ +/****************************************************************************** + * Copyright © 2013-2019 The Komodo Platform Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * Komodo Platform software, including this file may be copied, modified, * + * propagated or distributed except according to the terms contained in the * + * LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + +//! Our project +#include "atomic.dex.qt.internet.checker.service.hpp" +#include "atomic.dex.qt.utilities.hpp" +#include "atomic.threadpool.hpp" + +//! QT Properties +namespace atomic_dex +{ + void + atomic_dex::internet_service_checker::set_internet_alive(bool internet_status) noexcept + { + if (internet_status != is_internet_reacheable) + { + is_internet_reacheable = internet_status; + emit internetStatusChanged(); + } + } + + bool + atomic_dex::internet_service_checker::is_internet_alive() const noexcept + { + return is_internet_reacheable.load(); + } +} // namespace atomic_dex + +namespace atomic_dex +{ + internet_service_checker::internet_service_checker(entt::registry& registry, QObject* parent) : QObject(parent), system(registry) + { + m_update_clock = std::chrono::high_resolution_clock::now(); + } + + void + internet_service_checker::update() noexcept + { + using namespace std::chrono_literals; + + const auto now = std::chrono::high_resolution_clock::now(); + const auto s = std::chrono::duration_cast(now - m_update_clock); + if (s >= 30s) + { + this->fetch_internet_connection(); + m_update_clock = std::chrono::high_resolution_clock::now(); + } + } + + void + internet_service_checker::fetch_internet_connection() + { + spdlog::info("fetching internet status"); + spawn([this]() { + is_google_reacheable = am_i_able_to_reach_this_endpoint("https://www.google.com"); + is_paprika_provider_alive = am_i_able_to_reach_this_endpoint("https://api.coinpaprika.com/v1/coins/btc-bitcoin"); + bool res = is_google_reacheable || is_paprika_provider_alive || is_cipig_electrum_alive || is_our_private_endpoint_reacheable; + this->set_internet_alive(res); + }); + } +} // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.internet.checker.service.hpp b/src/atomic.dex.qt.internet.checker.service.hpp new file mode 100644 index 0000000000..d3daa9d60f --- /dev/null +++ b/src/atomic.dex.qt.internet.checker.service.hpp @@ -0,0 +1,65 @@ +/****************************************************************************** + * Copyright © 2013-2019 The Komodo Platform Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * Komodo Platform software, including this file may be copied, modified, * + * propagated or distributed except according to the terms contained in the * + * LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + +#pragma once + +//! QT +#include + +//! PCH +#include + +namespace atomic_dex +{ + class internet_service_checker final : public QObject, public ag::ecs::pre_update_system + { + //! Q_Object definition + Q_OBJECT + + Q_PROPERTY(bool internet_reacheable READ is_internet_alive WRITE set_internet_alive NOTIFY internetStatusChanged) + //! Private typedefs + using t_update_time_point = std::chrono::high_resolution_clock::time_point; + + //! Private members + t_update_time_point m_update_clock; + std::atomic_bool is_internet_reacheable{true}; + std::atomic_bool is_paprika_provider_alive{true}; + std::atomic_bool is_cipig_electrum_alive{true}; + std::atomic_bool is_google_reacheable{true}; + std::atomic_bool is_our_private_endpoint_reacheable{true}; + + //! Private functions + void fetch_internet_connection(); + + signals: + void internetStatusChanged(); + + public: + //! Constructor + explicit internet_service_checker(entt::registry& registry, QObject* parent = nullptr); + ~internet_service_checker() noexcept final = default; + + //! Public override + void update() noexcept final; + + //! QT Properties + [[nodiscard]] bool is_internet_alive() const noexcept; + + void set_internet_alive(bool internet_status) noexcept; + }; +} // namespace atomic_dex + +REFL_AUTO(type(atomic_dex::internet_service_checker)) \ No newline at end of file From 6d5e7578743bcf9b75a410e2bd2f7c45a89a188d Mon Sep 17 00:00:00 2001 From: milerius Date: Thu, 30 Jul 2020 12:59:42 +0200 Subject: [PATCH 097/515] feat(internet_services): plug internet fetcher to the program --- src/atomic.dex.app.cpp | 2 ++ src/atomic.dex.qt.internet.checker.service.cpp | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index 9b6cd91b0c..df0c3b4ce5 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -44,6 +44,7 @@ #include "atomic.dex.provider.cex.prices.hpp" #include "atomic.dex.provider.coinpaprika.hpp" #include "atomic.dex.qt.bindings.hpp" +#include "atomic.dex.qt.internet.checker.service.hpp" #include "atomic.dex.qt.utilities.hpp" #include "atomic.dex.security.hpp" #include "atomic.dex.update.service.hpp" @@ -430,6 +431,7 @@ namespace atomic_dex system_manager_.create_system(mm2_system, m_config); system_manager_.create_system(mm2_system); system_manager_.create_system(); + system_manager_.create_system(this); connect_signals(); if (is_there_a_default_wallet()) diff --git a/src/atomic.dex.qt.internet.checker.service.cpp b/src/atomic.dex.qt.internet.checker.service.cpp index cd9039affa..601a1c28a8 100644 --- a/src/atomic.dex.qt.internet.checker.service.cpp +++ b/src/atomic.dex.qt.internet.checker.service.cpp @@ -44,6 +44,7 @@ namespace atomic_dex internet_service_checker::internet_service_checker(entt::registry& registry, QObject* parent) : QObject(parent), system(registry) { m_update_clock = std::chrono::high_resolution_clock::now(); + this->fetch_internet_connection(); } void @@ -63,12 +64,13 @@ namespace atomic_dex void internet_service_checker::fetch_internet_connection() { - spdlog::info("fetching internet status"); + spdlog::info("fetching internet status begin"); spawn([this]() { is_google_reacheable = am_i_able_to_reach_this_endpoint("https://www.google.com"); is_paprika_provider_alive = am_i_able_to_reach_this_endpoint("https://api.coinpaprika.com/v1/coins/btc-bitcoin"); bool res = is_google_reacheable || is_paprika_provider_alive || is_cipig_electrum_alive || is_our_private_endpoint_reacheable; this->set_internet_alive(res); + spdlog::info("fetching internet status finished"); }); } } // namespace atomic_dex \ No newline at end of file From 20b4f40d6f4f3645445541ea1f2acc9e4b01fef1 Mon Sep 17 00:00:00 2001 From: naezith Date: Thu, 30 Jul 2020 14:16:26 +0300 Subject: [PATCH 098/515] feat(gui): allow low balance coins in dex --- atomic_qt_design/qml/Exchange/Trade/OrderForm.qml | 2 +- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index 51c17e54c3..25b1475f32 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -165,7 +165,7 @@ FloatingBackground { } function shouldBlockInput() { - return my_side && notEnoughBalanceForFees() + return my_side && (parseFloat(getMaxVolume()) < General.getMinTradeAmount() || notEnoughBalanceForFees()) } function onBaseChanged() { diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index f70baa0d30..fd5f9913bd 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -229,7 +229,7 @@ Item { return coins.filter(c => { c.balance = API.get().get_balance(c.ticker) - return c.balance !== '' && parseFloat(c.balance) >= General.getMinTradeAmount() + return true }) } // Filter for Receive @@ -403,6 +403,8 @@ Item { anchors.right: parent.right anchors.top: form_base.bottom anchors.topMargin: layout_margin + + field.enabled: form_base.field.enabled } // Show errors From c8e996e42a858ad296f46d1e042290a29226d008 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Thu, 30 Jul 2020 13:43:49 +0200 Subject: [PATCH 099/515] feat(buy/sell): add additional check for get trade infos Signed-off-by: romanszterg --- src/atomic.dex.app.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index 9b6cd91b0c..6997bb199a 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -916,6 +916,14 @@ namespace atomic_dex spdlog::debug("{} l{} f[{}]", __FUNCTION__, __LINE__, fs::path(__FILE__).filename().string()); QVariantMap out; + if (t_float_50(amount.toStdString()) < t_float_50("0.00777")) + { + out.insert("not_enough_balance_to_pay_the_fees", true); + out.insert("trade_fee", "0"); + out.insert("input_final_value", "0"); + out.insert("tx_fee", "0"); + return out; + } t_float_50 trade_fee_f = get_mm2().get_trade_fee(ticker.toStdString(), amount.toStdString(), false); auto answer = get_mm2().get_trade_fixed_fee(ticker.toStdString()); From 456de6a567c91569fc391ca56a033759311db752 Mon Sep 17 00:00:00 2001 From: naezith Date: Thu, 30 Jul 2020 15:07:33 +0300 Subject: [PATCH 100/515] feat(gui): propert inputbox amount and warning message for low balance coin --- atomic_qt_design/qml/Exchange/Trade/OrderForm.qml | 7 ++++++- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 8 +++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index 25b1475f32..e08876275c 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -106,6 +106,7 @@ FloatingBackground { if(!my_side) return valid // Sell side + if(valid) valid = !notEnoughBalance() if(valid) valid = API.get().do_i_have_enough_funds(getTicker(), input_volume.field.text) if(valid && hasEthFees()) valid = hasEnoughEthForFees() @@ -164,8 +165,12 @@ FloatingBackground { return false } + function notEnoughBalance() { + return my_side && parseFloat(getMaxVolume()) < General.getMinTradeAmount() + } + function shouldBlockInput() { - return my_side && (parseFloat(getMaxVolume()) < General.getMinTradeAmount() || notEnoughBalanceForFees()) + return my_side && (notEnoughBalance() || notEnoughBalanceForFees()) } function onBaseChanged() { diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index fd5f9913bd..cffb4cdf25 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -134,6 +134,10 @@ Item { return valid_trade_info && curr_trade_info.not_enough_balance_to_pay_the_fees } + function notEnoughBalance() { + return form_base.notEnoughBalance() + } + function getTradeInfo(base, rel, amount, set_as_current=true) { if(inCurrentPage()) { @@ -417,7 +421,9 @@ Item { font.pixelSize: Style.textSizeSmall4 color: Style.colorRed - text_value: API.get().empty_string + (notEnoughBalanceForFees() ? + text_value: API.get().empty_string + ( + notEnoughBalance() ? (qsTr("%1 balance is lower than minimum trade amount").arg(form_base.getTicker()) + " : " + General.getMinTradeAmount()) : + notEnoughBalanceForFees() ? (qsTr("Not enough balance for the fees. Need at least %1 more", "AMT TICKER").arg(General.formatCrypto("", parseFloat(curr_trade_info.amount_needed), form_base.getTicker()))) : (form_base.hasEthFees() && !form_base.hasEnoughEthForFees()) ? (qsTr("Not enough ETH for the transaction fee")) : (form_base.fieldsAreFilled() && !form_base.higherThanMinTradeAmount()) ? (qsTr("Sell amount is lower than minimum trade amount") + " : " + General.getMinTradeAmount()) : From 94e8cd45d73810241efa00801ebdfc5d7bc2b7eb Mon Sep 17 00:00:00 2001 From: romanszterg Date: Thu, 30 Jul 2020 16:19:48 +0200 Subject: [PATCH 101/515] feat(internet_checker): change the condition for internet check Signed-off-by: romanszterg --- src/atomic.dex.qt.internet.checker.service.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/atomic.dex.qt.internet.checker.service.cpp b/src/atomic.dex.qt.internet.checker.service.cpp index 601a1c28a8..0b6bafa818 100644 --- a/src/atomic.dex.qt.internet.checker.service.cpp +++ b/src/atomic.dex.qt.internet.checker.service.cpp @@ -68,9 +68,9 @@ namespace atomic_dex spawn([this]() { is_google_reacheable = am_i_able_to_reach_this_endpoint("https://www.google.com"); is_paprika_provider_alive = am_i_able_to_reach_this_endpoint("https://api.coinpaprika.com/v1/coins/btc-bitcoin"); - bool res = is_google_reacheable || is_paprika_provider_alive || is_cipig_electrum_alive || is_our_private_endpoint_reacheable; + bool res = is_google_reacheable || is_paprika_provider_alive; this->set_internet_alive(res); - spdlog::info("fetching internet status finished"); + spdlog::info("fetching internet status finished, internet status is: {}", res); }); } } // namespace atomic_dex \ No newline at end of file From e7d5625da670becb4a931b93677a049a9752c7c6 Mon Sep 17 00:00:00 2001 From: naezith Date: Thu, 30 Jul 2020 18:46:20 +0300 Subject: [PATCH 102/515] feat(gui): add TickerSelector, move ticker logic out of the forms --- .../qml/Exchange/Trade/OrderForm.qml | 96 +---------------- .../qml/Exchange/Trade/TickerSelector.qml | 100 ++++++++++++++++++ atomic_qt_design/qml/Exchange/Trade/Trade.qml | 58 +++++++--- qml.qrc | 1 + 4 files changed, 149 insertions(+), 106 deletions(-) create mode 100644 atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index e08876275c..e961ae505f 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -14,49 +14,10 @@ FloatingBackground { property bool enabled: true property alias column_layout: form_layout - property bool recursive_update: false - function getFiatText(v, ticker) { return General.formatFiat('', v === '' ? 0 : API.get().get_fiat_from_amount(ticker, v), API.get().current_fiat) + " " + General.cex_icon } - function update(new_ticker) { - updateTickerList(new_ticker) - } - - function inCurrentPage() { - return exchange_trade.inCurrentPage() - } - - property var ticker_list: ([]) - - function updateTickerList(new_ticker) { - recursive_update = new_ticker !== undefined - - ticker_list = my_side ? General.getTickersAndBalances(getFilteredCoins()) : General.getTickers(getFilteredCoins()) - - update_timer.running = true - } - - Timer { - id: update_timer - running: inCurrentPage() - repeat: true - interval: 1000 - onTriggered: { - if(inCurrentPage()) updateTickerList() - } - } - - - function setAnyTicker() { - setTicker(getAnyAvailableCoin()) - } - - function fillIfEmpty() { - if(getTicker() === '') setAnyTicker() - } - function canShowFees() { return my_side && valid_trade_info && !General.isZero(getVolume()) } @@ -65,21 +26,6 @@ FloatingBackground { return input_volume.field.text === '' ? '0' : input_volume.field.text } - function getFilteredCoins() { - return getCoins(my_side) - } - - function getAnyAvailableCoin(filter_ticker) { - let coins = getFilteredCoins().map(c => c.ticker) - - // Filter out ticker - if(filter_ticker !== undefined || filter_ticker !== '') - coins = coins.filter(c => c !== filter_ticker) - - // Pick a random one if prioritized ones do not satisfy - return coins.length > 0 ? coins[0] : '' - } - function fieldsAreFilled() { return input_volume.field.text !== '' } @@ -107,25 +53,14 @@ FloatingBackground { // Sell side if(valid) valid = !notEnoughBalance() - if(valid) valid = API.get().do_i_have_enough_funds(getTicker(), input_volume.field.text) + if(valid) valid = API.get().do_i_have_enough_funds(getTicker(my_side), input_volume.field.text) if(valid && hasEthFees()) valid = hasEnoughEthForFees() return valid } - function getTicker() { - return ticker_list.length > 0 ? ticker_list[combo.currentIndex].value : "" - } - - function setTicker(ticker) { - combo.currentIndex = getFilteredCoins().map(c => c.ticker).indexOf(ticker) - - // If it doesn't exist, pick an existing one - if(combo.currentIndex === -1) setAnyTicker() - } - function getMaxVolume() { - return API.get().get_balance(getTicker()) + return API.get().get_balance(getTicker(my_side)) } function getMaxTradableVolume(set_as_current) { @@ -220,31 +155,10 @@ FloatingBackground { } DefaultImage { - Layout.leftMargin: combo.Layout.rightMargin * 3 - source: General.coinIcon(getTicker()) + source: General.coinIcon(getTicker(my_side)) Layout.preferredWidth: 32 Layout.preferredHeight: Layout.preferredWidth } - - DefaultComboBox { - id: combo - - enabled: root.enabled - - Layout.fillWidth: true - - model: ticker_list - - - textRole: "text" - - onCurrentTextChanged: { - if(!recursive_update) { - updateForms(my_side, combo.currentText) - setPair(my_side) - } - } - } } @@ -303,7 +217,7 @@ FloatingBackground { anchors.top: input_volume.bottom anchors.topMargin: 5 - text_value: getFiatText(input_volume.field.text, getTicker()) + text_value: getFiatText(input_volume.field.text, getTicker(my_side)) font.pixelSize: input_volume.field.font.pixelSize CexInfoTrigger {} @@ -314,7 +228,7 @@ FloatingBackground { anchors.rightMargin: 10 anchors.verticalCenter: input_volume.verticalCenter - text_value: getTicker() + text_value: getTicker(my_side) font.pixelSize: input_volume.field.font.pixelSize } } diff --git a/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml b/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml new file mode 100644 index 0000000000..d9dd0a608e --- /dev/null +++ b/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml @@ -0,0 +1,100 @@ +import QtQuick 2.12 +import QtQuick.Layouts 1.12 +import QtQuick.Controls 2.12 +import QtGraphicalEffects 1.0 + +import "../../Components" +import "../../Constants" + +RowLayout { + id: root + + spacing: 5 + Layout.preferredWidth: 250 + layoutDirection: my_side ? Qt.LeftToRight : Qt.RightToLeft + + property bool my_side: false + property var ticker_list: ([]) + property bool recursive_update: false + + // Public + function setAnyTicker() { + setTicker(getAnyAvailableCoin()) + } + + function fillIfEmpty() { + if(getTicker() === '') setAnyTicker() + } + + function update(new_ticker) { + updateTickerList(new_ticker) + } + + function getTicker() { + return ticker_list.length > 0 ? ticker_list[combo.currentIndex].value : "" + } + + function setTicker(ticker) { + combo.currentIndex = getFilteredCoins().map(c => c.ticker).indexOf(ticker) + + // If it doesn't exist, pick an existing one + if(combo.currentIndex === -1) setAnyTicker() + } + + // Private + Timer { + id: update_timer + running: inCurrentPage() + repeat: true + interval: 1000 + onTriggered: { + if(inCurrentPage()) updateTickerList() + } + } + + function updateTickerList(new_ticker) { + recursive_update = new_ticker !== undefined + + ticker_list = my_side ? General.getTickersAndBalances(getFilteredCoins()) : General.getTickers(getFilteredCoins()) + + update_timer.running = true + } + + function getFilteredCoins() { + return getCoins(my_side) + } + + function getAnyAvailableCoin(filter_ticker) { + let coins = getFilteredCoins().map(c => c.ticker) + + // Filter out ticker + if(filter_ticker !== undefined || filter_ticker !== '') + coins = coins.filter(c => c !== filter_ticker) + + // Pick a random one if prioritized ones do not satisfy + return coins.length > 0 ? coins[0] : '' + } + + DefaultImage { + source: General.coinIcon(getTicker()) + Layout.preferredWidth: 32 + Layout.preferredHeight: Layout.preferredWidth + } + + DefaultComboBox { + id: combo + + Layout.fillWidth: true + + model: ticker_list + + textRole: "text" + + onCurrentTextChanged: { + if(!recursive_update) { + updateForms(my_side, combo.currentText) + setPair(my_side) + } + } + } +} diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index cffb4cdf25..e45b1dad2c 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -164,8 +164,8 @@ Item { // Orderbook function fillTickersIfEmpty() { - form_base.fillIfEmpty() - form_rel.fillIfEmpty() + selector_base.fillIfEmpty() + selector_rel.fillIfEmpty() } function updateTradeInfo(force=false) { @@ -197,14 +197,14 @@ Item { function updateForms(my_side, new_ticker) { if(my_side === undefined) { - form_base.update() - form_rel.update() + selector_base.update() + selector_rel.update() } else if(my_side) { - form_rel.update(new_ticker) + selector_rel.update(new_ticker) } else { - form_base.update(new_ticker) + selector_base.update(new_ticker) } } @@ -243,12 +243,12 @@ Item { } function getTicker(is_base) { - return is_base ? form_base.getTicker() : form_rel.getTicker() + return is_base ? selector_base.getTicker() : selector_rel.getTicker() } function setTicker(is_base, ticker) { - if(is_base) form_base.setTicker(ticker) - else form_rel.setTicker(ticker) + if(is_base) selector_base.setTicker(ticker) + else selector_rel.setTicker(ticker) } function validBaseRel() { @@ -261,7 +261,7 @@ Item { if(getTicker(true) === getTicker(false)) { // Base got selected, same as rel // Change rel ticker - form_rel.setAnyTicker() + selector_rel.setAnyTicker() } if(validBaseRel()) { @@ -317,7 +317,7 @@ Item { // No coins warning ColumnLayout { anchors.centerIn: parent - visible: form_base.ticker_list.length === 0 + visible: selector_base.ticker_list.length === 0 DefaultImage { Layout.alignment: Qt.AlignHCenter @@ -343,7 +343,7 @@ Item { spacing: layout_margin - visible: form_base.ticker_list.length > 0 + visible: selector_base.ticker_list.length > 0 anchors.fill: parent @@ -365,7 +365,7 @@ Item { anchors.left: parent.left anchors.right: parent.right anchors.top: parent.top - anchors.bottom: orderbook.top + anchors.bottom: selectors.top anchors.bottomMargin: layout_margin * 2 CandleStickChart { @@ -373,6 +373,34 @@ Item { } } + // Ticker Selectors + RowLayout { + id: selectors + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: orderbook.top + anchors.bottomMargin: 10 + spacing: 40 + + TickerSelector { + id: selector_base + my_side: true + Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter + } + + DefaultImage { + source: General.image_path + "trade_icon.svg" + fillMode: Image.PreserveAspectFit + Layout.preferredWidth: 16 + Layout.preferredHeight: Layout.preferredWidth + Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter + } + + TickerSelector { + id: selector_rel + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + } + } + Orderbook { id: orderbook height: 250 @@ -422,9 +450,9 @@ Item { color: Style.colorRed text_value: API.get().empty_string + ( - notEnoughBalance() ? (qsTr("%1 balance is lower than minimum trade amount").arg(form_base.getTicker()) + " : " + General.getMinTradeAmount()) : + notEnoughBalance() ? (qsTr("%1 balance is lower than minimum trade amount").arg(selector_base.getTicker()) + " : " + General.getMinTradeAmount()) : notEnoughBalanceForFees() ? - (qsTr("Not enough balance for the fees. Need at least %1 more", "AMT TICKER").arg(General.formatCrypto("", parseFloat(curr_trade_info.amount_needed), form_base.getTicker()))) : + (qsTr("Not enough balance for the fees. Need at least %1 more", "AMT TICKER").arg(General.formatCrypto("", parseFloat(curr_trade_info.amount_needed), selector_base.getTicker()))) : (form_base.hasEthFees() && !form_base.hasEnoughEthForFees()) ? (qsTr("Not enough ETH for the transaction fee")) : (form_base.fieldsAreFilled() && !form_base.higherThanMinTradeAmount()) ? (qsTr("Sell amount is lower than minimum trade amount") + " : " + General.getMinTradeAmount()) : (form_rel.fieldsAreFilled() && !form_rel.higherThanMinTradeAmount()) ? (qsTr("Receive amount is lower than minimum trade amount") + " : " + General.getMinTradeAmount()) : "" diff --git a/qml.qrc b/qml.qrc index 1dbb7230de..26b3aef5fe 100644 --- a/qml.qrc +++ b/qml.qrc @@ -110,6 +110,7 @@ atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml atomic_qt_design/qml/Exchange/Trade/Orderbook.qml atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml + atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml atomic_qt_design/qml/Exchange/Orders/Orders.qml atomic_qt_design/qml/Exchange/Orders/OrderList.qml atomic_qt_design/qml/Exchange/History/History.qml From 6fe477f55828fac2076bceff72f11deea6aa7382 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Fri, 31 Jul 2020 08:00:23 +0200 Subject: [PATCH 103/515] feat(internet_checker): add our private endpoint to the list of reacheable point Signed-off-by: romanszterg --- src/atomic.dex.qt.internet.checker.service.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/atomic.dex.qt.internet.checker.service.cpp b/src/atomic.dex.qt.internet.checker.service.cpp index 0b6bafa818..ff843b5625 100644 --- a/src/atomic.dex.qt.internet.checker.service.cpp +++ b/src/atomic.dex.qt.internet.checker.service.cpp @@ -68,7 +68,8 @@ namespace atomic_dex spawn([this]() { is_google_reacheable = am_i_able_to_reach_this_endpoint("https://www.google.com"); is_paprika_provider_alive = am_i_able_to_reach_this_endpoint("https://api.coinpaprika.com/v1/coins/btc-bitcoin"); - bool res = is_google_reacheable || is_paprika_provider_alive; + is_our_private_endpoint_reacheable = am_i_able_to_reach_this_endpoint("https://komodo.live:3333/api/v1/ohlc/tickers_list"); + bool res = is_google_reacheable || is_paprika_provider_alive || is_our_private_endpoint_reacheable; this->set_internet_alive(res); spdlog::info("fetching internet status finished, internet status is: {}", res); }); From 3d28259e31ea0d36eca2590ff9d17ae0ccbfa129 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Fri, 31 Jul 2020 11:35:19 +0200 Subject: [PATCH 104/515] feat(internet_checker): finalize internet checker with property Signed-off-by: romanszterg --- src/atomic.dex.app.cpp | 15 ++++++++++++--- src/atomic.dex.app.hpp | 6 ++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index df0c3b4ce5..494e279f5d 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -44,7 +44,6 @@ #include "atomic.dex.provider.cex.prices.hpp" #include "atomic.dex.provider.coinpaprika.hpp" #include "atomic.dex.qt.bindings.hpp" -#include "atomic.dex.qt.internet.checker.service.hpp" #include "atomic.dex.qt.utilities.hpp" #include "atomic.dex.security.hpp" #include "atomic.dex.update.service.hpp" @@ -423,7 +422,8 @@ namespace atomic_dex {"update_needed", false}, {"changelog", ""}, {"current_version", ""}, {"download_url", ""}, {"new_version", ""}, {"rpc_code", 0}, {"status", ""}}), m_coin_info(new current_coin_info(dispatcher_, this)), m_addressbook(new addressbook_model(this->m_wallet_manager, this)), m_portfolio(new portfolio_model(this->system_manager_, this->m_config, this)), m_orders(new orders_model(this->system_manager_, this)), - m_candlestick_chart_ohlc(new candlestick_charts_model(this->system_manager_, this)), m_orderbook(new qt_orderbook_wrapper(this->system_manager_, this)) + m_candlestick_chart_ohlc(new candlestick_charts_model(this->system_manager_, this)), m_orderbook(new qt_orderbook_wrapper(this->system_manager_, this)), + m_internet_service_checker(std::addressof(system_manager_.create_system(this))) { get_dispatcher().sink().connect<&application::on_refresh_update_status_event>(*this); //! MM2 system need to be created before the GUI and give the instance to the gui @@ -431,7 +431,6 @@ namespace atomic_dex system_manager_.create_system(mm2_system, m_config); system_manager_.create_system(mm2_system); system_manager_.create_system(); - system_manager_.create_system(this); connect_signals(); if (is_there_a_default_wallet()) @@ -1496,4 +1495,14 @@ namespace atomic_dex this->m_orderbook_need_a_reset = evt.is_a_reset; } } +} // namespace atomic_dex + +//! Internet checker +namespace atomic_dex +{ + internet_service_checker* + application::get_internet_checker() const noexcept + { + return m_internet_service_checker; + } } // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.app.hpp b/src/atomic.dex.app.hpp index b538fdd596..7688311a3d 100644 --- a/src/atomic.dex.app.hpp +++ b/src/atomic.dex.app.hpp @@ -36,6 +36,7 @@ #include "atomic.dex.qt.bindings.hpp" #include "atomic.dex.qt.candlestick.charts.model.hpp" #include "atomic.dex.qt.current.coin.infos.hpp" +#include "atomic.dex.qt.internet.checker.service.hpp" #include "atomic.dex.qt.orderbook.hpp" #include "atomic.dex.qt.orders.model.hpp" #include "atomic.dex.qt.portfolio.model.hpp" @@ -62,6 +63,7 @@ namespace atomic_dex Q_PROPERTY(candlestick_charts_model* candlestick_charts_mdl READ get_candlestick_charts NOTIFY candlestickChartsChanged) Q_PROPERTY(QVariant update_status READ get_update_status NOTIFY updateStatusChanged) Q_PROPERTY(portfolio_model* portfolio_mdl READ get_portfolio NOTIFY portfolioChanged) + Q_PROPERTY(internet_service_checker* internet_checker READ get_internet_checker) Q_PROPERTY(QString current_currency READ get_current_currency WRITE set_current_currency NOTIFY on_currency_changed) Q_PROPERTY(QString current_fiat READ get_current_fiat WRITE set_current_fiat NOTIFY on_fiat_changed) Q_PROPERTY(QString lang READ get_current_lang WRITE set_current_lang NOTIFY on_lang_changed) @@ -126,6 +128,7 @@ namespace atomic_dex portfolio_model* get_portfolio() const noexcept; orders_model* get_orders() const noexcept; candlestick_charts_model* get_candlestick_charts() const noexcept; + internet_service_checker* get_internet_checker() const noexcept;; qt_orderbook_wrapper* get_orderbook_wrapper() const noexcept; QVariantList get_enabled_coins() const noexcept; QVariantList get_enableable_coins() const noexcept; @@ -296,6 +299,9 @@ namespace atomic_dex qt_orderbook_wrapper* m_orderbook; std::atomic_bool m_orderbook_need_a_reset{false}; + //! Internet service checker + internet_service_checker* m_internet_service_checker; + std::atomic_bool m_about_to_exit_app{false}; }; } // namespace atomic_dex From da695ef65022c633f9ad5b2007e46424f8b92066 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Fri, 31 Jul 2020 11:57:28 +0200 Subject: [PATCH 105/515] feat(timezone): turn timezone manipulation into a utility function Signed-off-by: romanszterg --- src/atomic.dex.mm2.api.cpp | 22 ++++++---------------- src/atomic.dex.utilities.hpp | 17 +++++++++++++++++ 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/src/atomic.dex.mm2.api.cpp b/src/atomic.dex.mm2.api.cpp index 97baf8ef57..f6ecc954aa 100644 --- a/src/atomic.dex.mm2.api.cpp +++ b/src/atomic.dex.mm2.api.cpp @@ -19,6 +19,7 @@ //! Project Headers #include "atomic.dex.mm2.api.hpp" +#include "atomic.dex.utilities.hpp" //! Utilities namespace @@ -219,12 +220,8 @@ namespace mm2::api j.at("tx_hash").get_to(cfg.tx_hash); j.at("tx_hex").get_to(cfg.tx_hex); - using namespace date; - using namespace std::chrono; - date::sys_seconds tp{seconds{cfg.timestamp}}; - auto tp_zoned = date::make_zoned(current_zone(), tp); - std::string s = date::format("%e %b %Y, %I:%M", tp_zoned); - cfg.timestamp_as_date = std::move(s); + std::string s = to_human_date(cfg.timestamp, "%e %b %Y, %I:%M"); + cfg.timestamp_as_date = std::move(s); } void @@ -437,9 +434,7 @@ namespace mm2::api j.at("netid").get_to(answer.netid); j.at("timestamp").get_to(answer.timestamp); - sys_time tp{std::chrono::milliseconds{answer.timestamp}}; - auto tp_zoned = date::make_zoned(current_zone(), tp); - answer.human_timestamp = date::format("%Y-%m-%d %I:%M:%S", tp_zoned); + answer.human_timestamp = to_human_date(answer.timestamp, "%Y-%m-%d %I:%M:%S"); t_float_50 result_asks_f("0"); for (auto&& cur_asks: answer.asks) { result_asks_f = result_asks_f + t_float_50(cur_asks.maxvolume); } @@ -651,8 +646,6 @@ namespace mm2::api { using namespace date; const auto time_key = value.at("created_at").get(); - sys_time tp{std::chrono::milliseconds{time_key}}; - auto tp_zoned = date::make_zoned(current_zone(), tp); my_order_contents contents{ .order_id = key, .price = is_maker ? adjust_precision(value.at("price").get()) : "0", @@ -663,7 +656,7 @@ namespace mm2::api .order_type = is_maker ? "maker" : "taker", .base_amount = is_maker ? value.at("max_base_vol").get() : value.at("request").at("base_amount").get(), .rel_amount = is_maker ? (t_float_50(contents.price) * t_float_50(contents.base_amount)).convert_to() : value.at("request").at("rel_amount").get(), - .human_timestamp = date::format("%F %T", tp_zoned)}; + .human_timestamp = to_human_date(time_key, "%F %T")}; out.try_emplace(time_key, std::move(contents)); }; // clang-format on @@ -728,12 +721,9 @@ namespace mm2::api for (auto&& content: j.at("events")) { - using sys_milliseconds = sys_time; const nlohmann::json& j_evt = content.at("event"); auto timestamp = content.at("timestamp").get(); - auto tp = sys_milliseconds{std::chrono::milliseconds{timestamp}}; - auto tp_zoned = date::make_zoned(current_zone(), tp); - std::string human_date = date::format("%F %T", tp_zoned); + std::string human_date = to_human_date(timestamp, "%F %T"); auto evt_type = j_evt.at("type").get(); auto rate_bundler = [&event_timestamp_registry, diff --git a/src/atomic.dex.utilities.hpp b/src/atomic.dex.utilities.hpp index ff6e7cf4e7..8f735f5da6 100644 --- a/src/atomic.dex.utilities.hpp +++ b/src/atomic.dex.utilities.hpp @@ -8,6 +8,23 @@ #include "atomic.dex.pch.hpp" +template +inline std::string +to_human_date(std::size_t timestamp, std::string format) +{ + using namespace date; + const sys_time tp{TimeFormat{timestamp}}; + try + { + const auto tp_zoned = date::make_zoned(current_zone(), tp); + return date::format(std::move(format), tp_zoned); + } + catch (const std::exception& error) + { + return date::format(std::move(format), tp); + } +} + inline fs::path get_atomic_dex_data_folder() { From 9988212172eee922552b123bcb46e2a3b419e3d1 Mon Sep 17 00:00:00 2001 From: naezith Date: Fri, 31 Jul 2020 14:08:48 +0300 Subject: [PATCH 106/515] feat(gui): add right side text to textfield, add AmountFieldWithInfo --- .../qml/Components/AmountFieldWithInfo.qml | 17 +++++++++++++++++ .../qml/Components/DefaultTextField.qml | 12 ++++++++++++ .../qml/Exchange/Trade/OrderForm.qml | 14 ++------------ qml.qrc | 1 + 4 files changed, 32 insertions(+), 12 deletions(-) create mode 100644 atomic_qt_design/qml/Components/AmountFieldWithInfo.qml diff --git a/atomic_qt_design/qml/Components/AmountFieldWithInfo.qml b/atomic_qt_design/qml/Components/AmountFieldWithInfo.qml new file mode 100644 index 0000000000..e611f95b90 --- /dev/null +++ b/atomic_qt_design/qml/Components/AmountFieldWithInfo.qml @@ -0,0 +1,17 @@ +import QtQuick 2.12 +import QtQuick.Layouts 1.12 +import QtQuick.Controls 2.12 + +import "../Components" +import "../Constants" + +TextFieldWithTitle { + id: root + + field.validator: RegExpValidator { + regExp: /(0|([1-9][0-9]*))(\.[0-9]{1,8})?/ + } + + field.font.pixelSize: Style.textSizeSmall1 + field.font.weight: Font.Bold +} diff --git a/atomic_qt_design/qml/Components/DefaultTextField.qml b/atomic_qt_design/qml/Components/DefaultTextField.qml index 50540d0e4f..bc801e5f85 100644 --- a/atomic_qt_design/qml/Components/DefaultTextField.qml +++ b/atomic_qt_design/qml/Components/DefaultTextField.qml @@ -7,6 +7,8 @@ import "../Constants" TextField { id: text_field + property alias right_text: right_text.text_value + font.family: Style.font_family placeholderTextColor: Style.colorPlaceholderText @@ -19,6 +21,16 @@ TextField { } RightClickMenu { } + + DefaultText { + id: right_text + visible: text_value !== "" + anchors.right: parent.right + anchors.rightMargin: 10 + anchors.verticalCenter: parent.verticalCenter + + font.pixelSize: text_field.font.pixelSize + } } /*##^## diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index e961ae505f..f70a0ca9ab 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -180,7 +180,7 @@ FloatingBackground { Layout.fillWidth: true height: input_volume.height - AmountField { + AmountFieldWithInfo { id: input_volume width: parent.width field.enabled: root.enabled && !shouldBlockInput() @@ -208,8 +208,7 @@ FloatingBackground { if(field.activeFocus) resetPrice() } - field.font.pixelSize: Style.textSizeSmall1 - field.font.weight: Font.Bold + field.right_text: getTicker(my_side) } DefaultText { @@ -222,15 +221,6 @@ FloatingBackground { CexInfoTrigger {} } - - DefaultText { - anchors.right: input_volume.right - anchors.rightMargin: 10 - anchors.verticalCenter: input_volume.verticalCenter - - text_value: getTicker(my_side) - font.pixelSize: input_volume.field.font.pixelSize - } } } diff --git a/qml.qrc b/qml.qrc index 26b3aef5fe..0dc13f4aa8 100644 --- a/qml.qrc +++ b/qml.qrc @@ -135,6 +135,7 @@ atomic_qt_design/qml/Components/AddressField.qml atomic_qt_design/qml/Components/AddressFieldWithTitle.qml atomic_qt_design/qml/Components/AmountField.qml + atomic_qt_design/qml/Components/AmountFieldWithInfo.qml atomic_qt_design/qml/Components/AmountIntField.qml atomic_qt_design/qml/Components/CopyFieldButton.qml atomic_qt_design/qml/Components/HideFieldButton.qml From 7617beab7210a9e6fa4a705e7d00307836ca3be6 Mon Sep 17 00:00:00 2001 From: naezith Date: Fri, 31 Jul 2020 14:28:46 +0300 Subject: [PATCH 107/515] feat(gui): right align amount inputs, fit title into the inputbox --- .../qml/Components/AmountFieldWithInfo.qml | 2 + .../qml/Components/DefaultTextField.qml | 15 ++++ .../qml/Exchange/Trade/OrderForm.qml | 83 +++++++++---------- 3 files changed, 54 insertions(+), 46 deletions(-) diff --git a/atomic_qt_design/qml/Components/AmountFieldWithInfo.qml b/atomic_qt_design/qml/Components/AmountFieldWithInfo.qml index e611f95b90..e50cccb6b6 100644 --- a/atomic_qt_design/qml/Components/AmountFieldWithInfo.qml +++ b/atomic_qt_design/qml/Components/AmountFieldWithInfo.qml @@ -12,6 +12,8 @@ TextFieldWithTitle { regExp: /(0|([1-9][0-9]*))(\.[0-9]{1,8})?/ } + field.horizontalAlignment: Qt.AlignRight + field.font.pixelSize: Style.textSizeSmall1 field.font.weight: Font.Bold } diff --git a/atomic_qt_design/qml/Components/DefaultTextField.qml b/atomic_qt_design/qml/Components/DefaultTextField.qml index bc801e5f85..c228e85c99 100644 --- a/atomic_qt_design/qml/Components/DefaultTextField.qml +++ b/atomic_qt_design/qml/Components/DefaultTextField.qml @@ -7,6 +7,7 @@ import "../Constants" TextField { id: text_field + property alias left_text: left_text.text_value property alias right_text: right_text.text_value font.family: Style.font_family @@ -20,8 +21,22 @@ TextField { radius: 100 } + leftPadding: Math.max(0, left_text.width + 20) + rightPadding: Math.max(0, right_text.width + 20) + + RightClickMenu { } + DefaultText { + id: left_text + visible: text_value !== "" + anchors.left: parent.left + anchors.leftMargin: 10 + anchors.verticalCenter: parent.verticalCenter + + font.pixelSize: text_field.font.pixelSize + } + DefaultText { id: right_text visible: text_value !== "" diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index f70a0ca9ab..4e65f01bb3 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -166,65 +166,56 @@ FloatingBackground { Layout.fillWidth: true } - ColumnLayout { + Item { Layout.fillWidth: true Layout.leftMargin: top_line.Layout.leftMargin Layout.rightMargin: top_line.Layout.rightMargin - - DefaultText { - text_value: API.get().empty_string + (qsTr("Amount") + ':') - font.pixelSize: Style.textSizeSmall1 - } - - Item { - Layout.fillWidth: true - height: input_volume.height - - AmountFieldWithInfo { - id: input_volume - width: parent.width - field.enabled: root.enabled && !shouldBlockInput() - field.placeholderText: API.get().empty_string + (my_side ? qsTr("Amount to sell") : - field.enabled ? qsTr("Amount to receive") : qsTr("Please fill the send amount")) - field.onTextChanged: { - const before_checks = field.text - onBaseChanged() - const after_checks = field.text - - // Update slider only if the value is not from slider, or value got corrected here - if(before_checks !== after_checks || !input_volume_slider.updating_text_field) { - input_volume_slider.updating_from_text_field = true - input_volume_slider.value = parseFloat(field.text) - input_volume_slider.updating_from_text_field = false - } - } - - function resetPrice() { - if(!my_side && orderIsSelected()) resetPreferredPrice() + height: input_volume.height + + AmountFieldWithInfo { + id: input_volume + width: parent.width + field.enabled: root.enabled && !shouldBlockInput() + field.placeholderText: API.get().empty_string + (my_side ? qsTr("Amount to sell") : + field.enabled ? qsTr("Amount to receive") : qsTr("Please fill the send amount")) + field.onTextChanged: { + const before_checks = field.text + onBaseChanged() + const after_checks = field.text + + // Update slider only if the value is not from slider, or value got corrected here + if(before_checks !== after_checks || !input_volume_slider.updating_text_field) { + input_volume_slider.updating_from_text_field = true + input_volume_slider.value = parseFloat(field.text) + input_volume_slider.updating_from_text_field = false } + } - field.onPressed: resetPrice() - field.onFocusChanged: { - if(field.activeFocus) resetPrice() - } + function resetPrice() { + if(!my_side && orderIsSelected()) resetPreferredPrice() + } - field.right_text: getTicker(my_side) + field.onPressed: resetPrice() + field.onFocusChanged: { + if(field.activeFocus) resetPrice() } - DefaultText { - anchors.left: input_volume.left - anchors.top: input_volume.bottom - anchors.topMargin: 5 + field.left_text: API.get().empty_string + (qsTr("Volume")) + field.right_text: getTicker(my_side) + } + + DefaultText { + anchors.left: input_volume.left + anchors.top: input_volume.bottom + anchors.topMargin: 5 - text_value: getFiatText(input_volume.field.text, getTicker(my_side)) - font.pixelSize: input_volume.field.font.pixelSize + text_value: getFiatText(input_volume.field.text, getTicker(my_side)) + font.pixelSize: input_volume.field.font.pixelSize - CexInfoTrigger {} - } + CexInfoTrigger {} } } - Slider { id: input_volume_slider function getRealValue() { From 9a9fdc0f92ca9b38510e9669050fbbd165029dc0 Mon Sep 17 00:00:00 2001 From: naezith Date: Fri, 31 Jul 2020 14:52:16 +0300 Subject: [PATCH 108/515] feat(gui): dummy buy/sell forms --- .../qml/Exchange/Trade/OrderForm.qml | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index 4e65f01bb3..6899a41890 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -141,8 +141,8 @@ FloatingBackground { // Title DefaultText { - font.pixelSize: Style.textSizeMid2 - text_value: API.get().empty_string + (my_side ? qsTr("Sell") : qsTr("Receive")) + font.pixelSize: Style.textSize + text_value: API.get().empty_string + (my_side ? qsTr("Sell") : qsTr("Buy")) color: my_side ? Style.colorRed : Style.colorGreen font.weight: Font.Bold } @@ -153,12 +153,6 @@ FloatingBackground { Layout.leftMargin: 20 Layout.rightMargin: 20 } - - DefaultImage { - source: General.coinIcon(getTicker(my_side)) - Layout.preferredWidth: 32 - Layout.preferredHeight: Layout.preferredWidth - } } @@ -166,6 +160,18 @@ FloatingBackground { Layout.fillWidth: true } + AmountFieldWithInfo { + id: input_price + Layout.leftMargin: top_line.Layout.leftMargin + Layout.rightMargin: top_line.Layout.rightMargin + Layout.bottomMargin: -6 + Layout.fillWidth: true + field.enabled: root.enabled && !shouldBlockInput() + + field.left_text: API.get().empty_string + (qsTr("Price")) + field.right_text: getTicker(false) + } + Item { Layout.fillWidth: true Layout.leftMargin: top_line.Layout.leftMargin @@ -176,8 +182,10 @@ FloatingBackground { id: input_volume width: parent.width field.enabled: root.enabled && !shouldBlockInput() - field.placeholderText: API.get().empty_string + (my_side ? qsTr("Amount to sell") : - field.enabled ? qsTr("Amount to receive") : qsTr("Please fill the send amount")) + + field.left_text: API.get().empty_string + (qsTr("Volume")) + field.right_text: getTicker(true) + field.placeholderText: API.get().empty_string + (my_side ? qsTr("Amount to sell") : qsTr("Amount to receive")) field.onTextChanged: { const before_checks = field.text onBaseChanged() @@ -199,9 +207,6 @@ FloatingBackground { field.onFocusChanged: { if(field.activeFocus) resetPrice() } - - field.left_text: API.get().empty_string + (qsTr("Volume")) - field.right_text: getTicker(my_side) } DefaultText { @@ -355,10 +360,9 @@ FloatingBackground { Layout.rightMargin: top_line.Layout.rightMargin Layout.bottomMargin: layout_margin - visible: !my_side width: 170 - text: API.get().empty_string + (!preffered_order.is_asks && orderIsSelected() ? qsTr("Match Order") : qsTr("Create Order")) + text: API.get().empty_string + (my_side ? qsTr("Sell %1", "TICKER").arg(getTicker(true)) : qsTr("Buy %1", "TICKER").arg(getTicker(true))) enabled: valid_trade_info && !notEnoughBalanceForFees() && form_base.isValid() && form_rel.isValid() onClicked: confirm_trade_modal.open() } From 2a0bb00ff10d6c027d6c42969e21a3040e74b459 Mon Sep 17 00:00:00 2001 From: naezith Date: Fri, 31 Jul 2020 15:27:12 +0300 Subject: [PATCH 109/515] feat(gui): a lot better code for primary/danger/default button styling --- .../qml/Components/DangerButton.qml | 6 +-- .../qml/Components/DefaultButton.qml | 13 +++--- .../qml/Components/PrimaryButton.qml | 7 +-- atomic_qt_design/qml/Constants/Style.qml | 44 +++++++++++++------ 4 files changed, 39 insertions(+), 31 deletions(-) diff --git a/atomic_qt_design/qml/Components/DangerButton.qml b/atomic_qt_design/qml/Components/DangerButton.qml index 15c6d1f556..8f9be34650 100644 --- a/atomic_qt_design/qml/Components/DangerButton.qml +++ b/atomic_qt_design/qml/Components/DangerButton.qml @@ -5,11 +5,7 @@ import QtQuick.Controls 2.12 import "../Constants" DefaultButton { - colorDisabled: Style.colorButtonDangerDisabled - colorHovered: Style.colorButtonDangerHovered - colorEnabled: Style.colorButtonDangerEnabled - colorTextDisabled: Style.colorWhite8 - colorTextEnabled: Style.colorWhite1 + button_type: "danger" } /*##^## diff --git a/atomic_qt_design/qml/Components/DefaultButton.qml b/atomic_qt_design/qml/Components/DefaultButton.qml index 6af6da47d6..c4aefa4b06 100644 --- a/atomic_qt_design/qml/Components/DefaultButton.qml +++ b/atomic_qt_design/qml/Components/DefaultButton.qml @@ -13,12 +13,13 @@ FloatingBackground { property bool text_left_align: false property double text_offset: 0 property alias font: text_obj.font - property string colorDisabled: Style.colorButtonDisabled - property string colorHovered: Style.colorButtonHovered - property string colorEnabled: Style.colorButtonEnabled - property string colorTextDisabled: Style.colorButtonTextDisabled - property string colorTextHovered: Style.colorButtonTextHovered - property string colorTextEnabled: Style.colorButtonTextEnabled + property string button_type: "default" + property string colorDisabled: Style.colorButtonDisabled[button_type] + property string colorHovered: Style.colorButtonHovered[button_type] + property string colorEnabled: Style.colorButtonEnabled[button_type] + property string colorTextDisabled: Style.colorButtonTextDisabled[button_type] + property string colorTextHovered: Style.colorButtonTextHovered[button_type] + property string colorTextEnabled: Style.colorButtonTextEnabled[button_type] property int minWidth: 90 signal clicked() diff --git a/atomic_qt_design/qml/Components/PrimaryButton.qml b/atomic_qt_design/qml/Components/PrimaryButton.qml index 44d9454c41..47fae4a3e6 100644 --- a/atomic_qt_design/qml/Components/PrimaryButton.qml +++ b/atomic_qt_design/qml/Components/PrimaryButton.qml @@ -5,12 +5,7 @@ import QtQuick.Controls 2.12 import "../Constants" DefaultButton { - colorDisabled: Style.colorButtonPrimaryDisabled - colorHovered: Style.colorButtonPrimaryHovered - colorEnabled: Style.colorButtonPrimaryEnabled - colorTextDisabled: Style.colorWhite13 - colorTextEnabled: Style.colorWhite10 - colorTextHovered: Style.colorWhite10 + button_type: "primary" font.bold: true } diff --git a/atomic_qt_design/qml/Constants/Style.qml b/atomic_qt_design/qml/Constants/Style.qml index a51259c54e..1cefe7b352 100644 --- a/atomic_qt_design/qml/Constants/Style.qml +++ b/atomic_qt_design/qml/Constants/Style.qml @@ -159,22 +159,38 @@ QtObject { readonly property string colorText: dark_theme ? Style.colorWhite1 : "#405366" readonly property string colorText2: dark_theme ? "#79808C" : "#3C5368" readonly property string colorTextDisabled: dark_theme ? Style.colorWhite8 : "#B5B9C1" - readonly property string colorButtonDisabled: Style.colorTheme9 - readonly property string colorButtonHovered: Style.colorTheme6 - readonly property string colorButtonEnabled: Style.colorRectangle - readonly property string colorButtonTextDisabled: Style.colorWhite8 - readonly property string colorButtonTextHovered: Style.colorText - readonly property string colorButtonTextEnabled: Style.colorText + readonly property var colorButtonDisabled: ({ + "default": Style.colorTheme9, + "primary": Style.colorGreen3, + "danger": Style.colorRed3 + }) + readonly property var colorButtonHovered: ({ + "default": Style.colorTheme6, + "primary": Style.colorGreen, + "danger": Style.colorRed + }) + readonly property var colorButtonEnabled: ({ + "default": Style.colorRectangle, + "primary": Style.colorGreen2, + "danger": Style.colorRed2 + }) + readonly property var colorButtonTextDisabled: ({ + "default": Style.colorWhite8, + "primary": Style.colorWhite13, + "danger": Style.colorWhite8 + }) + readonly property var colorButtonTextHovered: ({ + "default": Style.colorText, + "primary": Style.colorWhite10, + "danger": Style.colorWhite8 + }) + readonly property var colorButtonTextEnabled: ({ + "default": Style.colorText, + "primary": Style.colorWhite10, + "danger": Style.colorWhite1 + }) readonly property string colorPlaceholderText: Style.colorWhite9 - property string colorButtonDangerDisabled: Style.colorRed3 - property string colorButtonDangerHovered: Style.colorRed - property string colorButtonDangerEnabled: Style.colorRed2 - - property string colorButtonPrimaryDisabled: Style.colorGreen3 - property string colorButtonPrimaryHovered: Style.colorGreen - property string colorButtonPrimaryEnabled: Style.colorGreen2 - readonly property int modalTitleMargin: 10 readonly property string modalValueColor: colorWhite4 From 84eb89bad51bbc337cfe63c6c430c93a890f2d64 Mon Sep 17 00:00:00 2001 From: naezith Date: Fri, 31 Jul 2020 15:31:11 +0300 Subject: [PATCH 110/515] feat(gui): combine buy/sell forms with a toggle --- .../qml/Exchange/Trade/OrderForm.qml | 25 +++++++++++-------- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 11 +++++--- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index 6899a41890..dd067a5289 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -135,23 +135,27 @@ FloatingBackground { // Top Line RowLayout { id: top_line + spacing: 20 Layout.topMargin: parent.spacing Layout.leftMargin: parent.spacing*2 Layout.rightMargin: Layout.leftMargin + Layout.alignment: Qt.AlignHCenter - // Title - DefaultText { + DefaultButton { font.pixelSize: Style.textSize - text_value: API.get().empty_string + (my_side ? qsTr("Sell") : qsTr("Buy")) - color: my_side ? Style.colorRed : Style.colorGreen + text: API.get().empty_string + (qsTr("Sell")) + color: sell_mode ? Style.colorRed : Style.colorRed3 + colorTextEnabled: sell_mode ? Style.colorWhite1 : Style.colorWhite6 font.weight: Font.Bold + onClicked: sell_mode = true } - - Arrow { - up: my_side - color: my_side ? Style.colorRed : Style.colorGreen - Layout.leftMargin: 20 - Layout.rightMargin: 20 + DefaultButton { + font.pixelSize: Style.textSize + text: API.get().empty_string + (qsTr("Buy")) + color: sell_mode ? Style.colorGreen3 : Style.colorGreen + colorTextEnabled: sell_mode ? Style.colorWhite8 : Style.colorWhite1 + font.weight: Font.Bold + onClicked: sell_mode = false } } @@ -355,6 +359,7 @@ FloatingBackground { // Trade button DefaultButton { + button_type: my_side ? "primary" : "danger" Layout.alignment: Qt.AlignRight | Qt.AlignBottom Layout.topMargin: 5 Layout.rightMargin: top_line.Layout.rightMargin diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index e45b1dad2c..c76a2b23e7 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -11,6 +11,8 @@ Item { property string action_result + property bool sell_mode: true + // Override property var onOrderSuccess: () => {} @@ -22,6 +24,7 @@ Item { function fullReset() { reset(true) + sell_mode = true } function reset(reset_result=true, is_base) { @@ -420,6 +423,7 @@ Item { // Sell OrderForm { id: form_base + visible: sell_mode anchors.left: parent.left anchors.right: parent.right @@ -431,10 +435,11 @@ Item { // Receive OrderForm { id: form_rel + visible: !form_base.visible + anchors.left: parent.left anchors.right: parent.right - anchors.top: form_base.bottom - anchors.topMargin: layout_margin + anchors.top: parent.top field.enabled: form_base.field.enabled } @@ -443,7 +448,7 @@ Item { DefaultText { anchors.left: parent.left anchors.right: parent.right - anchors.top: form_rel.bottom + anchors.top: form_base.visible ? form_base.bottom : form_rel.bottom anchors.topMargin: layout_margin * 2 font.pixelSize: Style.textSizeSmall4 From 1f679c0a4a10488b7dee31e9319cb87da45a9ff9 Mon Sep 17 00:00:00 2001 From: naezith Date: Fri, 31 Jul 2020 15:41:44 +0300 Subject: [PATCH 111/515] feat(gui): move selectors to top --- .../qml/Components/PlusButton.qml | 4 +-- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 31 ++++++++++--------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/atomic_qt_design/qml/Components/PlusButton.qml b/atomic_qt_design/qml/Components/PlusButton.qml index 84db8781d0..f72529c29d 100644 --- a/atomic_qt_design/qml/Components/PlusButton.qml +++ b/atomic_qt_design/qml/Components/PlusButton.qml @@ -17,6 +17,6 @@ DefaultButton { verticalShadow: true - colorEnabled: Style.colorButtonHovered - colorHovered: Style.colorButtonEnabled + colorEnabled: Style.colorButtonHovered[button_type] + colorHovered: Style.colorButtonEnabled[button_type] } diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index c76a2b23e7..99e13e246f 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -362,26 +362,12 @@ Item { anchors.bottom: parent.bottom anchors.rightMargin: layout_margin - InnerBackground { - id: graph_bg - - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.bottom: selectors.top - anchors.bottomMargin: layout_margin * 2 - - CandleStickChart { - anchors.fill: parent - } - } // Ticker Selectors RowLayout { id: selectors anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: orderbook.top - anchors.bottomMargin: 10 + anchors.top: parent.top spacing: 40 TickerSelector { @@ -404,6 +390,21 @@ Item { } } + InnerBackground { + id: graph_bg + + anchors.left: parent.left + anchors.right: parent.right + anchors.top: selectors.bottom + anchors.topMargin: layout_margin + anchors.bottom: orderbook.top + anchors.bottomMargin: layout_margin * 2 + + CandleStickChart { + anchors.fill: parent + } + } + Orderbook { id: orderbook height: 250 From a7aa7ba8f868ac83fd771686e7d3ea51f774216d Mon Sep 17 00:00:00 2001 From: naezith Date: Fri, 31 Jul 2020 16:14:16 +0300 Subject: [PATCH 112/515] feat(gui): smaller spacing --- atomic_qt_design/qml/Exchange/Trade/OrderForm.qml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index dd067a5289..a0d82d1629 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -137,7 +137,7 @@ FloatingBackground { id: top_line spacing: 20 Layout.topMargin: parent.spacing - Layout.leftMargin: parent.spacing*2 + Layout.leftMargin: parent.spacing Layout.rightMargin: Layout.leftMargin Layout.alignment: Qt.AlignHCenter @@ -239,7 +239,7 @@ FloatingBackground { Layout.fillWidth: true Layout.leftMargin: top_line.Layout.leftMargin Layout.rightMargin: top_line.Layout.rightMargin - Layout.bottomMargin: top_line.Layout.rightMargin + Layout.bottomMargin: top_line.Layout.rightMargin*0.25 from: 0 stepSize: 1/Math.pow(10, precision) to: parseFloat(getMaxVolume()) @@ -297,7 +297,6 @@ FloatingBackground { Layout.fillWidth: true Layout.leftMargin: top_line.Layout.leftMargin Layout.rightMargin: top_line.Layout.rightMargin - Layout.bottomMargin: layout_margin content: RowLayout { width: bg.width From be5b404ccd002552aa829c81cedcf06285f00249 Mon Sep 17 00:00:00 2001 From: naezith Date: Fri, 31 Jul 2020 16:47:54 +0300 Subject: [PATCH 113/515] feat(gui): fill price field --- atomic_qt_design/qml/Constants/General.qml | 2 +- .../qml/Exchange/Trade/OrderForm.qml | 5 +++++ atomic_qt_design/qml/Exchange/Trade/Trade.qml | 18 +++++++++++++----- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/atomic_qt_design/qml/Constants/General.qml b/atomic_qt_design/qml/Constants/General.qml index ac770af3b5..74f89c7e17 100644 --- a/atomic_qt_design/qml/Constants/General.qml +++ b/atomic_qt_design/qml/Constants/General.qml @@ -187,7 +187,7 @@ QtObject { } function isZero(v) { - return parseFloat(v) === 0 + return !fieldExists(v) || parseFloat(v) === 0 } function fieldExists(v) { diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index a0d82d1629..6d5ab0ebb0 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -10,6 +10,7 @@ FloatingBackground { id: root property alias field: input_volume.field + property alias price_field: input_price.field property bool my_side: false property bool enabled: true property alias column_layout: form_layout @@ -174,6 +175,10 @@ FloatingBackground { field.left_text: API.get().empty_string + (qsTr("Price")) field.right_text: getTicker(false) + + field.onTextChanged: { + if(field.text !== preffered_order.price) resetPreferredPrice() + } } Item { diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index 99e13e246f..5f14f16852 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -60,6 +60,10 @@ Item { preffered_order.price_denom = price_denom preffered_order.price_numer = price_numer preffered_order = preffered_order + + form_base.price_field.text = price + form_rel.price_field.text = price + updateRelAmount() form_base.field.forceActiveFocus() } @@ -97,10 +101,14 @@ Item { } function getCalculatedPrice() { - const base = form_base.getVolume() - const rel = form_rel.getVolume() - - return General.isZero(base) || General.isZero(rel) ? "0" : API.get().get_price_amount(base, rel) + if(sell_mode) { + let sell_price = form_base.price_field.text + return General.isZero(sell_price) ? "0" : sell_price + } + else { + let buy_price = form_rel.price_field.text + return General.isZero(buy_price) ? "0" : buy_price + } } function getCurrentPrice() { @@ -108,7 +116,7 @@ Item { } function hasValidPrice() { - return orderIsSelected() || parseFloat(getCalculatedPrice()) !== 0 + return orderIsSelected() || !General.isZero(getCalculatedPrice()) } // Cache Trade Info From 3dad95993901903947c63c9b64c85af55f9208d4 Mon Sep 17 00:00:00 2001 From: naezith Date: Fri, 31 Jul 2020 17:18:46 +0300 Subject: [PATCH 114/515] feat(gui): change trade mode on order select --- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index 5f14f16852..c8c3e2f987 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -54,6 +54,8 @@ Item { } function selectOrder(is_asks, price, quantity, price_denom, price_numer) { + sell_mode = !is_asks + preffered_order.is_asks = is_asks preffered_order.price = price preffered_order.volume = quantity From d7d37935a5a6f250b81f20a1874d7dad6d7bbeaa Mon Sep 17 00:00:00 2001 From: romanszterg Date: Fri, 31 Jul 2020 16:29:05 +0200 Subject: [PATCH 115/515] feat(multiple_currency): first part of multicurrency support Signed-off-by: romanszterg --- assets/config/cfg.json | 33 ++++++++++++++++++++++++- src/atomic.dex.cfg.hpp | 10 ++++---- src/atomic.dex.provider.coinpaprika.cpp | 16 +++++++++--- src/atomic.dex.provider.coinpaprika.hpp | 12 ++++++--- 4 files changed, 58 insertions(+), 13 deletions(-) diff --git a/assets/config/cfg.json b/assets/config/cfg.json index dd43e26fd6..5b5712e54f 100644 --- a/assets/config/cfg.json +++ b/assets/config/cfg.json @@ -9,7 +9,38 @@ "current_fiat": "USD", "available_fiat": [ "USD", - "EUR" + "EUR", + "GBP", + "HKD", + "IDR", + "ILS", + "DKK", + "INR", + "CHF", + "MXN", + "CZK", + "SGD", + "THB", + "HRK", + "MYR", + "NOK", + "CNY", + "BGN", + "PHP", + "PLN", + "ZAR", + "CAD", + "ISK", + "BRL", + "RON", + "NZD", + "TRY", + "JPY", + "RUB", + "KRW", + "AUD", + "HUF", + "SEK" ], "possible_currencies": [ "USD", diff --git a/src/atomic.dex.cfg.hpp b/src/atomic.dex.cfg.hpp index cd802f6f71..926a1d36d6 100644 --- a/src/atomic.dex.cfg.hpp +++ b/src/atomic.dex.cfg.hpp @@ -30,10 +30,10 @@ namespace atomic_dex std::array possible_currencies; }; - void from_json(const nlohmann::json& j, cfg& config); - void change_lang(cfg& config, const std::string& new_lang); - void change_currency(cfg& config, const std::string& new_currency); - void change_fiat(cfg& config, const std::string& new_fiat); + void from_json(const nlohmann::json& j, cfg& config); + void change_lang(cfg& config, const std::string& new_lang); + void change_currency(cfg& config, const std::string& new_currency); + void change_fiat(cfg& config, const std::string& new_fiat); [[nodiscard]] bool is_this_currency_a_fiat(cfg& config, const std::string& currency) noexcept; - cfg load_cfg(); + cfg load_cfg(); } // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.provider.coinpaprika.cpp b/src/atomic.dex.provider.coinpaprika.cpp index 2314eb2057..8f530e3fe8 100644 --- a/src/atomic.dex.provider.coinpaprika.cpp +++ b/src/atomic.dex.provider.coinpaprika.cpp @@ -279,7 +279,7 @@ namespace atomic_dex } } - std::size_t default_precision = (fiat == "USD" || fiat == "EUR") ? 2 : 8; + std::size_t default_precision = is_this_currency_a_fiat(m_cfg, fiat) ? 2 : 8; ss.precision(default_precision); ss << std::fixed << final_price_f; std::string result = ss.str(); @@ -380,13 +380,23 @@ namespace atomic_dex } current_price = m_kmd_rate_providers.at(ticker); } + else + { + //! Todo pickup from api open rates + if (m_usd_rate_providers.find(ticker) == m_usd_rate_providers.cend()) + { + ec = dextop_error::unknown_ticker_for_rate_conversion; + return "0.00"; + } + current_price = m_usd_rate_providers.at(ticker); + } if (adjusted) { - std::size_t default_precision = (fiat == "USD" || fiat == "EUR") ? 2 : 8; + std::size_t default_precision = is_this_currency_a_fiat(m_cfg, fiat) ? 2 : 8; t_float_50 current_price_f(current_price); - if (fiat == "USD" || fiat == "EUR") + if (is_this_currency_a_fiat(m_cfg, fiat)) { if (current_price_f < 1.0) { diff --git a/src/atomic.dex.provider.coinpaprika.hpp b/src/atomic.dex.provider.coinpaprika.hpp index 2737be25b1..e747e4192d 100644 --- a/src/atomic.dex.provider.coinpaprika.hpp +++ b/src/atomic.dex.provider.coinpaprika.hpp @@ -20,9 +20,9 @@ #include "atomic.dex.pch.hpp" //! Project Headers +#include "atomic.dex.cfg.hpp" #include "atomic.dex.events.hpp" #include "atomic.dex.mm2.hpp" -#include "atomic.dex.cfg.hpp" #include "atomic.dex.provider.coinpaprika.api.hpp" namespace atomic_dex @@ -49,7 +49,9 @@ namespace atomic_dex t_providers_registry m_kmd_rate_providers{}; t_ticker_infos_registry m_ticker_infos_registry{}; t_ticker_historical_registry m_ticker_historical_registry{}; - t_supported_fiat_registry m_supported_fiat_registry{"USD", "EUR", "BTC", "KMD"}; + t_supported_fiat_registry m_supported_fiat_registry{"USD", "EUR", "BTC", "KMD", "GBP", "HKD", "IDR", "ILS", "DKK", "INR", "CHF", "MXN", + "CZK", "SGD", "THB", "HRK", "MYR", "NOK", "CNY", "BGN", "PHP", "PLN", "ZAR", "CAD", + "ISK", "BRL", "RON", "NZD", "TRY", "JPY", "RUB", "KRW", "AUD", "HUF", "SEK"}; std::thread m_provider_rates_thread; timed_waiter m_provider_thread_timer; @@ -70,10 +72,12 @@ namespace atomic_dex std::string get_price_in_fiat_all(const std::string& fiat, std::error_code& ec) const noexcept; //! Get the price in currency from a transaction. - std::string get_price_as_currency_from_tx(const std::string& currency, const std::string& ticker, const tx_infos& tx, std::error_code& ec) const noexcept; + std::string + get_price_as_currency_from_tx(const std::string& currency, const std::string& ticker, const tx_infos& tx, std::error_code& ec) const noexcept; //! Get the price in currency from a fees. - std::string get_price_as_currency_from_amount(const std::string& currency, const std::string& ticker, const std::string& amount, std::error_code& ec) const noexcept; + std::string get_price_as_currency_from_amount( + const std::string& currency, const std::string& ticker, const std::string& amount, std::error_code& ec) const noexcept; //! Get the cex rates base / rel eg: VRSC / KMD = price of usd VRSC / KMD price USD std::string get_cex_rates(const std::string& base, const std::string& rel, std::error_code& ec) const noexcept; From 620d34d35b772f513d80664498efb5e4c474bfa3 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Fri, 31 Jul 2020 16:47:45 +0200 Subject: [PATCH 116/515] feat(cfg): add symbol sign Signed-off-by: romanszterg --- assets/config/cfg.json | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/assets/config/cfg.json b/assets/config/cfg.json index 5b5712e54f..ff60a63df2 100644 --- a/assets/config/cfg.json +++ b/assets/config/cfg.json @@ -7,6 +7,47 @@ ], "current_currency": "USD", "current_fiat": "USD", + "current_sign": "$", + "available_signs": [ + { + "USD": "$", + "EUR": "€", + "GBP": "£", + "HKD": "HK$", + "IDR": "IDR", + "ILS": "₪", + "DKK": "DKK", + "INR": "₹", + "CHF": "CHF", + "MXN": "MXN", + "CZK": "CZK", + "SGD": "SGD", + "THB": "฿", + "HRK": "kn", + "MYR": "MYR", + "NOK": "NOK", + "CNY": "¥", + "BGN": "лв", + "PHP": "₱", + "PLN": "zł", + "ZAR": "R", + "CAD": "$CA", + "ISK": "ISK", + "BRL": "R$", + "RON": "RON", + "NZD": "NZ$", + "TRY": "₺", + "JPY": "¥", + "RUB": "₽", + "KRW": "₩", + "AUD": "$A", + "HUF": "Ft", + "SEK": "kr", + "KMD": "KMD", + "BTC": "₿", + "BTC_ALT": "฿" + } + ], "available_fiat": [ "USD", "EUR", From 36261a704d4caae4064c38216bea7a374efb8faa Mon Sep 17 00:00:00 2001 From: romanszterg Date: Fri, 31 Jul 2020 16:49:06 +0200 Subject: [PATCH 117/515] feat(available_sign): as a single object Signed-off-by: romanszterg --- assets/config/cfg.json | 78 ++++++++++++++++++++---------------------- 1 file changed, 38 insertions(+), 40 deletions(-) diff --git a/assets/config/cfg.json b/assets/config/cfg.json index ff60a63df2..6dfe6222b9 100644 --- a/assets/config/cfg.json +++ b/assets/config/cfg.json @@ -8,46 +8,44 @@ "current_currency": "USD", "current_fiat": "USD", "current_sign": "$", - "available_signs": [ - { - "USD": "$", - "EUR": "€", - "GBP": "£", - "HKD": "HK$", - "IDR": "IDR", - "ILS": "₪", - "DKK": "DKK", - "INR": "₹", - "CHF": "CHF", - "MXN": "MXN", - "CZK": "CZK", - "SGD": "SGD", - "THB": "฿", - "HRK": "kn", - "MYR": "MYR", - "NOK": "NOK", - "CNY": "¥", - "BGN": "лв", - "PHP": "₱", - "PLN": "zł", - "ZAR": "R", - "CAD": "$CA", - "ISK": "ISK", - "BRL": "R$", - "RON": "RON", - "NZD": "NZ$", - "TRY": "₺", - "JPY": "¥", - "RUB": "₽", - "KRW": "₩", - "AUD": "$A", - "HUF": "Ft", - "SEK": "kr", - "KMD": "KMD", - "BTC": "₿", - "BTC_ALT": "฿" - } - ], + "available_signs": { + "USD": "$", + "EUR": "€", + "GBP": "£", + "HKD": "HK$", + "IDR": "IDR", + "ILS": "₪", + "DKK": "DKK", + "INR": "₹", + "CHF": "CHF", + "MXN": "MXN", + "CZK": "CZK", + "SGD": "SGD", + "THB": "฿", + "HRK": "kn", + "MYR": "MYR", + "NOK": "NOK", + "CNY": "¥", + "BGN": "лв", + "PHP": "₱", + "PLN": "zł", + "ZAR": "R", + "CAD": "$CA", + "ISK": "ISK", + "BRL": "R$", + "RON": "RON", + "NZD": "NZ$", + "TRY": "₺", + "JPY": "¥", + "RUB": "₽", + "KRW": "₩", + "AUD": "$A", + "HUF": "Ft", + "SEK": "kr", + "KMD": "KMD", + "BTC": "₿", + "BTC_ALT": "฿" + }, "available_fiat": [ "USD", "EUR", From 0b1d1c65d0f0a975a2d5507a05e64057ddba986e Mon Sep 17 00:00:00 2001 From: naezith Date: Fri, 31 Jul 2020 17:56:58 +0300 Subject: [PATCH 118/515] feat(gui): add receive amount --- .../qml/Exchange/Trade/ConfirmTradeModal.qml | 4 +- .../qml/Exchange/Trade/OrderForm.qml | 66 ++++++++++++++++--- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 51 +++++--------- 3 files changed, 75 insertions(+), 46 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml index c103367b69..8570f81c48 100644 --- a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml +++ b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml @@ -32,8 +32,8 @@ DefaultModal { details: ({ base_coin: getTicker(true), rel_coin: getTicker(false), - base_amount: form_base.field.text, - rel_amount: form_rel.field.text, + base_amount: getCurrentForm().field.text, + rel_amount: getCurrentForm().receive_amount, order_id: '', date: '', diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index 6d5ab0ebb0..bd4c708c8a 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -14,6 +14,39 @@ FloatingBackground { property bool my_side: false property bool enabled: true property alias column_layout: form_layout + property string receive_amount: "0" + + function updateRelAmount() { + const price = parseFloat(getCurrentPrice()) + const base_volume = parseFloat(getVolume()) + let new_rel = base_volume * price + + // If an order is selected + if(orderIsSelected()) { + const selected_order = preffered_order + // If it's a bid order, cap the volume + if(!selected_order.is_asks) { + // If new rel volume is higher than the order max volume + const max_rel_volume = parseFloat(selected_order.volume) + if(new_rel > max_rel_volume) { + new_rel = max_rel_volume + + // Set base depending on the capped rel + const max_base_volume = max_rel_volume / price + if(base_volume !== max_base_volume) { + const new_base_text = General.formatDouble(max_base_volume) + if(input_volume.field.text !== new_base_text) + input_volume.field.text = new_base_text + } + } + } + } + + // Set rel + const new_rel_text = General.formatDouble(new_rel) + if(receive_amount !== new_rel_text) + receive_amount = new_rel_text + } function getFiatText(v, ticker) { return General.formatFiat('', v === '' ? 0 : API.get().get_fiat_from_amount(ticker, v), API.get().current_fiat) + " " + General.cex_icon @@ -361,19 +394,34 @@ FloatingBackground { } } - // Trade button - DefaultButton { - button_type: my_side ? "primary" : "danger" - Layout.alignment: Qt.AlignRight | Qt.AlignBottom + RowLayout { + Layout.alignment: Qt.AlignBottom Layout.topMargin: 5 - Layout.rightMargin: top_line.Layout.rightMargin + Layout.fillWidth: true + Layout.leftMargin: top_line.Layout.rightMargin + Layout.rightMargin: Layout.leftMargin Layout.bottomMargin: layout_margin - width: 170 + DefaultText { + Layout.alignment: Qt.AlignLeft + text_value: API.get().empty_string + (qsTr("Receive") + ": " + General.formatCrypto("", receive_amount, getTicker(!my_side))) + font.pixelSize: Style.textSizeSmall3 + } + + // Trade button + DefaultButton { + Layout.alignment: Qt.AlignRight + Layout.fillWidth: true + Layout.leftMargin: 30 - text: API.get().empty_string + (my_side ? qsTr("Sell %1", "TICKER").arg(getTicker(true)) : qsTr("Buy %1", "TICKER").arg(getTicker(true))) - enabled: valid_trade_info && !notEnoughBalanceForFees() && form_base.isValid() && form_rel.isValid() - onClicked: confirm_trade_modal.open() + button_type: my_side ? "danger" : "primary" + + width: 170 + + text: API.get().empty_string + (my_side ? qsTr("Sell %1", "TICKER").arg(getTicker(true)) : qsTr("Buy %1", "TICKER").arg(getTicker(true))) + enabled: valid_trade_info && !notEnoughBalanceForFees() && isValid() + onClicked: confirm_trade_modal.open() + } } } } diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index c8c3e2f987..9d35df9166 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -16,6 +16,10 @@ Item { // Override property var onOrderSuccess: () => {} + function getCurrentForm() { + return sell_mode ? form_base : form_rel + } + // Local function inCurrentPage() { return exchange.inCurrentPage() && @@ -66,40 +70,10 @@ Item { form_base.price_field.text = price form_rel.price_field.text = price - updateRelAmount() - form_base.field.forceActiveFocus() - } - - function newRelVolume(price) { - return parseFloat(form_base.getVolume()) * parseFloat(price) - } - - function updateRelAmount() { - if(orderIsSelected()) { - const price = parseFloat(preffered_order.price) - let new_rel = newRelVolume(preffered_order.price) - - if(!preffered_order.is_asks) { - // If new rel volume is higher than the order max volume - const max_volume = parseFloat(preffered_order.volume) - if(new_rel > max_volume) { - new_rel = max_volume - - // Set base - const max_base_volume = max_volume / price - if(parseFloat(form_base.getVolume()) !== max_base_volume) { - const new_base_text = General.formatDouble(max_base_volume) - if(form_base.field.text !== new_base_text) - form_base.field.text = new_base_text - } - } - } + form_base.updateRelAmount() + form_rel.updateRelAmount() - // Set rel - const new_rel_text = General.formatDouble(new_rel) - if(form_rel.field.text !== new_rel_text) - form_rel.field.text = new_rel_text - } + form_base.field.forceActiveFocus() } function getCalculatedPrice() { @@ -154,6 +128,13 @@ Item { function getTradeInfo(base, rel, amount, set_as_current=true) { if(inCurrentPage()) { + // Swap the trade info because of buy / sell, amount is already correct + if(!sell_mode) { + const tmp = base + base = rel + rel = tmp + } + let info = API.get().get_trade_infos(base, rel, amount) console.log("Getting Trade info with parameters: ", base, rel, amount, " - Result: ", JSON.stringify(info)) @@ -184,14 +165,14 @@ Item { function updateTradeInfo(force=false) { const base = getTicker(true) const rel = getTicker(false) - const amount = form_base.getVolume() + const amount = getCurrentForm().getVolume() if(force || (base !== undefined && rel !== undefined && amount !== undefined && base !== '' && rel !== '' && amount !== '' && amount !== '0')) { getTradeInfo(base, rel, amount) // Since new implementation does not update fees instantly, re-cap the volume every time, just in case - form_base.capVolume() + getCurrentForm().capVolume() } } From 7714afb062a6b65b391e778973b825dfa2db3b27 Mon Sep 17 00:00:00 2001 From: naezith Date: Fri, 31 Jul 2020 17:57:39 +0300 Subject: [PATCH 119/515] feat(gui): reset price field at coin change --- atomic_qt_design/qml/Exchange/Trade/OrderForm.qml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index bd4c708c8a..771c545f67 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -108,6 +108,8 @@ FloatingBackground { } function reset(is_base) { + input_price.field.text = '' + if(my_side) { // is_base info comes from the ComboBox ticker change in OrderForm. // At other places it's not given. From 282e49481b89c78a5cd184c4961e969b86340520 Mon Sep 17 00:00:00 2001 From: naezith Date: Fri, 31 Jul 2020 18:07:16 +0300 Subject: [PATCH 120/515] feat(gui): reset everything at buy/sell mode change --- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index 9d35df9166..8b60850fd0 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -20,6 +20,8 @@ Item { return sell_mode ? form_base : form_rel } + onSell_modeChanged: reset() + // Local function inCurrentPage() { return exchange.inCurrentPage() && @@ -67,8 +69,9 @@ Item { preffered_order.price_numer = price_numer preffered_order = preffered_order - form_base.price_field.text = price - form_rel.price_field.text = price + const price_text = General.formatDouble(price) + form_base.price_field.text = price_text + form_rel.price_field.text = price_text form_base.updateRelAmount() form_rel.updateRelAmount() From dd52dd61797f7db1d123c4b433cd21183057783e Mon Sep 17 00:00:00 2001 From: milerius Date: Sat, 1 Aug 2020 08:54:16 +0200 Subject: [PATCH 121/515] feat(multiple_currencies): finalize backend --- src/atomic.dex.provider.coinpaprika.cpp | 21 +++++++++++++++++++-- src/atomic.dex.provider.coinpaprika.hpp | 2 ++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/atomic.dex.provider.coinpaprika.cpp b/src/atomic.dex.provider.coinpaprika.cpp index 8f530e3fe8..de10301787 100644 --- a/src/atomic.dex.provider.coinpaprika.cpp +++ b/src/atomic.dex.provider.coinpaprika.cpp @@ -26,6 +26,20 @@ namespace using namespace atomic_dex; using namespace atomic_dex::coinpaprika::api; + nlohmann::json + fetch_fiat_rates() + { + nlohmann::json resp; + auto answer = RestClient::get("https://api.openrates.io/latest?base=USD"); + if (answer.code != 200) + { + spdlog::warn("unable to fetch last open rates"); + return resp; + } + resp = nlohmann::json::parse(answer.body); + return resp; + } + template void retry(TAnswer& answer, const TRequest& request, TFunctorRequest&& functor) @@ -175,7 +189,8 @@ namespace atomic_dex std::vector> out_fut; - out_fut.reserve(coins.size() * 6); + out_fut.reserve(coins.size() * 6 + 1); + out_fut.push_back(spawn([this]() { this->m_other_fiats_rates = fetch_fiat_rates(); })); for (auto&& current_coin: coins) { if (current_coin.coinpaprika_id == "test-coin") @@ -383,12 +398,14 @@ namespace atomic_dex else { //! Todo pickup from api open rates + if (m_usd_rate_providers.find(ticker) == m_usd_rate_providers.cend()) { ec = dextop_error::unknown_ticker_for_rate_conversion; return "0.00"; } - current_price = m_usd_rate_providers.at(ticker); + t_float_50 tmp_current_price = t_float_50(m_usd_rate_providers.at(ticker)) * m_other_fiats_rates->at("rates").at(fiat).get(); + current_price = tmp_current_price.str(); } if (adjusted) diff --git a/src/atomic.dex.provider.coinpaprika.hpp b/src/atomic.dex.provider.coinpaprika.hpp index e747e4192d..5e67f97c82 100644 --- a/src/atomic.dex.provider.coinpaprika.hpp +++ b/src/atomic.dex.provider.coinpaprika.hpp @@ -37,12 +37,14 @@ namespace atomic_dex private: //! Typedefs + using t_json_synchronized = boost::synchronized_value; using t_providers_registry = t_concurrent_reg; using t_supported_fiat_registry = std::unordered_set; //! Private fields mm2& m_mm2_instance; atomic_dex::cfg& m_cfg; + t_json_synchronized m_other_fiats_rates; t_providers_registry m_usd_rate_providers{}; t_providers_registry m_eur_rate_providers{}; t_providers_registry m_btc_rate_providers{}; From 136ccca8b1be5633f1e8a2b90066e3603eadbc13 Mon Sep 17 00:00:00 2001 From: naezith Date: Sat, 1 Aug 2020 14:22:25 +0300 Subject: [PATCH 122/515] feat(gui): cap volume and set price on bid order select --- .../qml/Exchange/Trade/OrderForm.qml | 51 +++++++++++-------- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 4 +- 2 files changed, 33 insertions(+), 22 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index 771c545f67..c668c27800 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -16,36 +16,46 @@ FloatingBackground { property alias column_layout: form_layout property string receive_amount: "0" - function updateRelAmount() { + function updateRelAmount(set_order_volume) { const price = parseFloat(getCurrentPrice()) const base_volume = parseFloat(getVolume()) - let new_rel = base_volume * price + let new_receive = base_volume * price // If an order is selected if(orderIsSelected()) { const selected_order = preffered_order - // If it's a bid order, cap the volume + // If it's a bid order, This is the sell side, + // Cap the volume with the order volume if(!selected_order.is_asks) { - // If new rel volume is higher than the order max volume - const max_rel_volume = parseFloat(selected_order.volume) - if(new_rel > max_rel_volume) { - new_rel = max_rel_volume - - // Set base depending on the capped rel - const max_base_volume = max_rel_volume / price - if(base_volume !== max_base_volume) { - const new_base_text = General.formatDouble(max_base_volume) - if(input_volume.field.text !== new_base_text) - input_volume.field.text = new_base_text - } + const order_buy_volume = parseFloat(selected_order.volume) + if(set_order_volume || parseFloat(getVolume()) > order_buy_volume) { + const new_sell_volume = General.formatDouble(order_buy_volume) + input_volume.field.text = new_sell_volume + + // Calculate new receive amount + new_receive = order_buy_volume * price } + +// // If new rel volume is higher than the order max volume +// const max_rel_volume = parseFloat(selected_order.volume) +// if(new_receive > max_rel_volume) { +// new_receive = max_rel_volume + +// // Set base depending on the capped rel +// const max_base_volume = max_rel_volume / price +// if(base_volume !== max_base_volume) { +// const new_base_text = General.formatDouble(max_base_volume) +// if(input_volume.field.text !== new_base_text) +// input_volume.field.text = new_base_text +// } +// } } } // Set rel - const new_rel_text = General.formatDouble(new_rel) - if(receive_amount !== new_rel_text) - receive_amount = new_rel_text + const new_receive_text = General.formatDouble(new_receive) + if(receive_amount !== new_receive_text) + receive_amount = new_receive_text } function getFiatText(v, ticker) { @@ -144,7 +154,7 @@ FloatingBackground { return my_side && (notEnoughBalance() || notEnoughBalanceForFees()) } - function onBaseChanged() { + function onInputChanged() { if(capVolume()) updateTradeInfo() if(my_side) { @@ -213,6 +223,7 @@ FloatingBackground { field.onTextChanged: { if(field.text !== preffered_order.price) resetPreferredPrice() + onInputChanged() } } @@ -232,7 +243,7 @@ FloatingBackground { field.placeholderText: API.get().empty_string + (my_side ? qsTr("Amount to sell") : qsTr("Amount to receive")) field.onTextChanged: { const before_checks = field.text - onBaseChanged() + onInputChanged() const after_checks = field.text // Update slider only if the value is not from slider, or value got corrected here diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index 8b60850fd0..3c9b669840 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -73,8 +73,8 @@ Item { form_base.price_field.text = price_text form_rel.price_field.text = price_text - form_base.updateRelAmount() - form_rel.updateRelAmount() + form_base.updateRelAmount(true) + form_rel.updateRelAmount(true) form_base.field.forceActiveFocus() } From 86ae0d4ca0d4cbb7bc2eabed6650cebd9a8fce25 Mon Sep 17 00:00:00 2001 From: naezith Date: Sat, 1 Aug 2020 14:35:10 +0300 Subject: [PATCH 123/515] feat(gui): deselect order when price box is interacted --- .../qml/Exchange/Trade/OrderForm.qml | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index c668c27800..45cecd5078 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -222,9 +222,17 @@ FloatingBackground { field.right_text: getTicker(false) field.onTextChanged: { - if(field.text !== preffered_order.price) resetPreferredPrice() onInputChanged() } + + function resetPrice() { + if(orderIsSelected()) resetPreferredPrice() + } + + field.onPressed: resetPrice() + field.onFocusChanged: { + if(field.activeFocus) resetPrice() + } } Item { @@ -253,15 +261,6 @@ FloatingBackground { input_volume_slider.updating_from_text_field = false } } - - function resetPrice() { - if(!my_side && orderIsSelected()) resetPreferredPrice() - } - - field.onPressed: resetPrice() - field.onFocusChanged: { - if(field.activeFocus) resetPrice() - } } DefaultText { From 27eb09b9194e3214924e5583b8314d59a51743ee Mon Sep 17 00:00:00 2001 From: naezith Date: Sat, 1 Aug 2020 14:43:52 +0300 Subject: [PATCH 124/515] feat(gui): display fees section for buy part --- .../qml/Exchange/Trade/OrderForm.qml | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index 45cecd5078..17e06a07ad 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -62,10 +62,6 @@ FloatingBackground { return General.formatFiat('', v === '' ? 0 : API.get().get_fiat_from_amount(ticker, v), API.get().current_fiat) + " " + General.cex_icon } - function canShowFees() { - return my_side && valid_trade_info && !General.isZero(getVolume()) - } - function getVolume() { return input_volume.field.text === '' ? '0' : input_volume.field.text } @@ -239,6 +235,7 @@ FloatingBackground { Layout.fillWidth: true Layout.leftMargin: top_line.Layout.leftMargin Layout.rightMargin: top_line.Layout.rightMargin + Layout.bottomMargin: input_volume.field.font.pixelSize height: input_volume.height AmountFieldWithInfo { @@ -340,8 +337,6 @@ FloatingBackground { // Fees InnerBackground { - visible: my_side - radius: 100 id: bg Layout.fillWidth: true @@ -354,7 +349,7 @@ FloatingBackground { ColumnLayout { id: fees - visible: canShowFees() + visible: valid_trade_info && !General.isZero(getVolume()) spacing: -2 Layout.leftMargin: 10 @@ -363,14 +358,14 @@ FloatingBackground { DefaultText { id: tx_fee_text - text_value: API.get().empty_string + ((qsTr('Transaction Fee') + ': ' + General.formatCrypto("", curr_trade_info.tx_fee, curr_trade_info.is_ticker_of_fees_eth ? "ETH" : getTicker(true))) + + text_value: API.get().empty_string + ((qsTr('Transaction Fee') + ': ' + General.formatCrypto("", curr_trade_info.tx_fee, curr_trade_info.is_ticker_of_fees_eth ? "ETH" : getTicker(my_side))) + // ETH Fees (hasEthFees() ? " + " + General.formatCrypto("", curr_trade_info.erc_fees, 'ETH') : '') + // Fiat part (" ("+ getFiatText(!hasEthFees() ? curr_trade_info.tx_fee : General.formatDouble((parseFloat(curr_trade_info.tx_fee) + parseFloat(curr_trade_info.erc_fees))), - curr_trade_info.is_ticker_of_fees_eth ? 'ETH' : getTicker(true)) + curr_trade_info.is_ticker_of_fees_eth ? 'ETH' : getTicker(my_side)) +")") @@ -381,11 +376,11 @@ FloatingBackground { } DefaultText { - text_value: API.get().empty_string + (qsTr('Trading Fee') + ': ' + General.formatCrypto("", curr_trade_info.trade_fee, getTicker(true)) + + text_value: API.get().empty_string + (qsTr('Trading Fee') + ': ' + General.formatCrypto("", curr_trade_info.trade_fee, getTicker(my_side)) + // Fiat part (" ("+ - getFiatText(curr_trade_info.trade_fee, getTicker(true)) + getFiatText(curr_trade_info.trade_fee, getTicker(my_side)) +")") ) font.pixelSize: tx_fee_text.font.pixelSize From bd4adda03c280c25bf9ab6554d9079694bb2c091 Mon Sep 17 00:00:00 2001 From: naezith Date: Sat, 1 Aug 2020 16:17:19 +0300 Subject: [PATCH 125/515] feat(gui): cap buy volume with order volume --- .../qml/Exchange/Trade/ConfirmTradeModal.qml | 2 +- .../qml/Exchange/Trade/OrderForm.qml | 37 ++++++++----------- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml index 8570f81c48..6bf7a8ddcb 100644 --- a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml +++ b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml @@ -33,7 +33,7 @@ DefaultModal { base_coin: getTicker(true), rel_coin: getTicker(false), base_amount: getCurrentForm().field.text, - rel_amount: getCurrentForm().receive_amount, + rel_amount: getCurrentForm().total_amount, order_id: '', date: '', diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index 17e06a07ad..830ef64f1f 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -14,7 +14,7 @@ FloatingBackground { property bool my_side: false property bool enabled: true property alias column_layout: form_layout - property string receive_amount: "0" + property string total_amount: "0" function updateRelAmount(set_order_volume) { const price = parseFloat(getCurrentPrice()) @@ -24,17 +24,15 @@ FloatingBackground { // If an order is selected if(orderIsSelected()) { const selected_order = preffered_order - // If it's a bid order, This is the sell side, // Cap the volume with the order volume - if(!selected_order.is_asks) { - const order_buy_volume = parseFloat(selected_order.volume) - if(set_order_volume || parseFloat(getVolume()) > order_buy_volume) { - const new_sell_volume = General.formatDouble(order_buy_volume) - input_volume.field.text = new_sell_volume - - // Calculate new receive amount - new_receive = order_buy_volume * price - } + const order_buy_volume = parseFloat(selected_order.volume) + if(set_order_volume || parseFloat(getVolume()) > order_buy_volume) { + const new_sell_volume = General.formatDouble(order_buy_volume) + input_volume.field.text = new_sell_volume + + // Calculate new receive amount + new_receive = order_buy_volume * price + } // // If new rel volume is higher than the order max volume // const max_rel_volume = parseFloat(selected_order.volume) @@ -49,13 +47,12 @@ FloatingBackground { // input_volume.field.text = new_base_text // } // } - } } // Set rel const new_receive_text = General.formatDouble(new_receive) - if(receive_amount !== new_receive_text) - receive_amount = new_receive_text + if(total_amount !== new_receive_text) + total_amount = new_receive_text } function getFiatText(v, ticker) { @@ -153,13 +150,11 @@ FloatingBackground { function onInputChanged() { if(capVolume()) updateTradeInfo() - if(my_side) { - // Rel is dependant on Base if price is set so update that - updateRelAmount() + // Rel is dependant on Base if price is set so update that + updateRelAmount() - // Update the new fees, input_volume might be changed - updateTradeInfo() - } + // Update the new fees, input_volume might be changed + updateTradeInfo() } implicitHeight: form_layout.height @@ -411,7 +406,7 @@ FloatingBackground { DefaultText { Layout.alignment: Qt.AlignLeft - text_value: API.get().empty_string + (qsTr("Receive") + ": " + General.formatCrypto("", receive_amount, getTicker(!my_side))) + text_value: API.get().empty_string + (qsTr("Total") + ": " + General.formatCrypto("", total_amount, getTicker(false))) font.pixelSize: Style.textSizeSmall3 } From 7d0c5d5163ba3fc0622ef38884327a605e6dc94f Mon Sep 17 00:00:00 2001 From: naezith Date: Sat, 1 Aug 2020 16:21:11 +0300 Subject: [PATCH 126/515] feat(gui): show balances at rel side ticker list --- atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml | 2 +- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml b/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml index d9dd0a608e..3391b24090 100644 --- a/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml +++ b/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml @@ -55,7 +55,7 @@ RowLayout { function updateTickerList(new_ticker) { recursive_update = new_ticker !== undefined - ticker_list = my_side ? General.getTickersAndBalances(getFilteredCoins()) : General.getTickers(getFilteredCoins()) + ticker_list = General.getTickersAndBalances(getFilteredCoins()) update_timer.running = true } diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index 3c9b669840..ec50c177f0 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -235,7 +235,13 @@ Item { } // Filter for Receive else { - return coins.filter(c => c.ticker !== getTicker(true)) + return coins.filter(c => { + if(c.ticker === getTicker(true)) return false + + c.balance = API.get().get_balance(c.ticker) + + return true + }) } } From c65b128adb6dc64f7c524badef672daf6f7fc722 Mon Sep 17 00:00:00 2001 From: naezith Date: Sat, 1 Aug 2020 16:26:34 +0300 Subject: [PATCH 127/515] feat(gui): reverse confirm trade modal sides for buy --- atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml index 6bf7a8ddcb..b483bdc41c 100644 --- a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml +++ b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml @@ -30,10 +30,10 @@ DefaultModal { Layout.alignment: Qt.AlignHCenter details: ({ - base_coin: getTicker(true), - rel_coin: getTicker(false), - base_amount: getCurrentForm().field.text, - rel_amount: getCurrentForm().total_amount, + base_coin: getTicker(sell_mode), + rel_coin: getTicker(!sell_mode), + base_amount: sell_mode ? getCurrentForm().field.text : getCurrentForm().total_amount, + rel_amount: sell_mode ? getCurrentForm().total_amount : getCurrentForm().field.text, order_id: '', date: '', From bca85bd1e5629bcd21c4a7b73e0d079c223a53b1 Mon Sep 17 00:00:00 2001 From: Roman Sztergbaum Date: Sat, 1 Aug 2020 16:07:13 +0200 Subject: [PATCH 128/515] enhancments(dpi): force passthrough for the rounding policy --- main.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/main.cpp b/main.cpp index 9764ec4fdb..0a5139b80b 100644 --- a/main.cpp +++ b/main.cpp @@ -45,6 +45,11 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) #endif { +#if defined(WIN32) + std::ostringstream env_app; + env_app << "QT_SCALE_FACTOR_ROUNDING_POLICY=PassThrough"; + _putenv(env_app.str().c_str()); +#endif std::signal(SIGABRT, signal_handler); //! Project #if defined(_WIN32) || defined(WIN32) @@ -89,6 +94,7 @@ main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) //! QT QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + //QCoreAppliation::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); int ac = 0; std::shared_ptr app = std::make_shared(ac, nullptr); From 5bcab038292940ff93a529ff7de17b2260505486 Mon Sep 17 00:00:00 2001 From: Roman Sztergbaum Date: Sat, 1 Aug 2020 17:54:21 +0200 Subject: [PATCH 129/515] feat(dpi): experimental 1.0 global scale factor --- main.cpp | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/main.cpp b/main.cpp index 0a5139b80b..b99e11a9ca 100644 --- a/main.cpp +++ b/main.cpp @@ -2,6 +2,8 @@ #include #include #include +#include +#include #include #define QZXING_QML @@ -93,11 +95,33 @@ main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) atomic_dex::application atomic_app; //! QT - QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + //SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); + QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling); //QCoreAppliation::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); int ac = 0; std::shared_ptr app = std::make_shared(ac, nullptr); - + + #if defined(WIN32) + QList sk = app->screens(); + std::string factor_list; + const double min_window_size = 800.0; + for (auto &&cur_screen : sk) { + double height = cur_screen->devicePixelRatio() * cur_screen->availableSize().height(); + //auto width = cur_screen->devicePixelRatio() * cur_screen->availableSize().width(); + + double current_scale = cur_screen->devicePixelRatio(); + spdlog::trace("checking if {} * {} > {} res: {}", current_scale, min_window_size, height, current_scale * min_window_size); + if (current_scale * min_window_size > height) { + current_scale = height / min_window_size; + } + factor_list += std::to_string(current_scale) + ","; + } + factor_list = factor_list.substr(0, factor_list.size() -1); + qputenv("QT_AUTO_SCREEN_SCALE_FACTOR", "0"); + spdlog::trace("factor_list: {}", factor_list); + qputenv("QT_SCREEN_SCALE_FACTORS", QString::fromStdString(factor_list).toUtf8()); + #endif + atomic_app.set_qt_app(app); //! QT QML From 83e96be0371a2ae5a177cd98ca84d65704a3ddfc Mon Sep 17 00:00:00 2001 From: Roman Sztergbaum Date: Sat, 1 Aug 2020 19:42:16 +0200 Subject: [PATCH 130/515] feat(dpi): finalize logic for flooring --- main.cpp | 57 +++++++++++++++++++++++++------------------------------- 1 file changed, 25 insertions(+), 32 deletions(-) diff --git a/main.cpp b/main.cpp index b99e11a9ca..6600e887bd 100644 --- a/main.cpp +++ b/main.cpp @@ -47,11 +47,9 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) #endif { -#if defined(WIN32) - std::ostringstream env_app; - env_app << "QT_SCALE_FACTOR_ROUNDING_POLICY=PassThrough"; - _putenv(env_app.str().c_str()); -#endif + // Determine if we pass through or floor + //SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); + std::signal(SIGABRT, signal_handler); //! Project #if defined(_WIN32) || defined(WIN32) @@ -88,40 +86,35 @@ main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) spdlog::set_pattern("[%H:%M:%S %z] [%L] [thr %t] %v"); spdlog::info("Logger successfully initialized"); - // spdlog::info("asan report: {}", (fs::temp_directory_path() / "asan.log").string().c_str()); - //__sanitizer_set_report_path((fs::temp_directory_path() / "asan.log").string().c_str()); - + bool should_floor = false; + { + int ac = 0; + QApplication tmp(ac, nullptr); + double min_window_size = 800.0; + auto screens = tmp.screens(); + for (auto&& cur_screen : screens) { + spdlog::trace("physical dpi: {}", cur_screen->physicalDotsPerInch()); + spdlog::trace("logical dpi: {}", cur_screen->logicalDotsPerInch()); + double scale = cur_screen->logicalDotsPerInch() / 96.0; + spdlog::trace("scale: {}", scale); + + double height = cur_screen->availableSize().height(); + spdlog::trace("height: {}", height); + if (scale * min_window_size > height) { + should_floor = true; + spdlog::trace("should floor"); + } + } + } + QGuiApplication::setHighDpiScaleFactorRoundingPolicy(should_floor ? Qt::HighDpiScaleFactorRoundingPolicy::Floor : Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); + QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling); //! App declaration atomic_dex::application atomic_app; //! QT - //SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); - QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling); - //QCoreAppliation::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); int ac = 0; std::shared_ptr app = std::make_shared(ac, nullptr); - #if defined(WIN32) - QList sk = app->screens(); - std::string factor_list; - const double min_window_size = 800.0; - for (auto &&cur_screen : sk) { - double height = cur_screen->devicePixelRatio() * cur_screen->availableSize().height(); - //auto width = cur_screen->devicePixelRatio() * cur_screen->availableSize().width(); - - double current_scale = cur_screen->devicePixelRatio(); - spdlog::trace("checking if {} * {} > {} res: {}", current_scale, min_window_size, height, current_scale * min_window_size); - if (current_scale * min_window_size > height) { - current_scale = height / min_window_size; - } - factor_list += std::to_string(current_scale) + ","; - } - factor_list = factor_list.substr(0, factor_list.size() -1); - qputenv("QT_AUTO_SCREEN_SCALE_FACTOR", "0"); - spdlog::trace("factor_list: {}", factor_list); - qputenv("QT_SCREEN_SCALE_FACTORS", QString::fromStdString(factor_list).toUtf8()); - #endif - atomic_app.set_qt_app(app); //! QT QML From c76475cf529db2ccb854b980e7bdac89d7af0229 Mon Sep 17 00:00:00 2001 From: Roman Sztergbaum Date: Sat, 1 Aug 2020 19:48:31 +0200 Subject: [PATCH 131/515] disable high dpi if flooring is required --- main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.cpp b/main.cpp index 6600e887bd..6969c648c4 100644 --- a/main.cpp +++ b/main.cpp @@ -107,7 +107,7 @@ main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) } } QGuiApplication::setHighDpiScaleFactorRoundingPolicy(should_floor ? Qt::HighDpiScaleFactorRoundingPolicy::Floor : Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); - QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QGuiApplication::setAttribute(should_floor ? Qt::AA_DisableHighDpiScaling : Qt::AA_EnableHighDpiScaling); //! App declaration atomic_dex::application atomic_app; From abb30108f2c5ec379bbb21f3e297036cfd65f95d Mon Sep 17 00:00:00 2001 From: milerius Date: Sun, 2 Aug 2020 06:57:32 +0200 Subject: [PATCH 132/515] feat(currency_signs): add all currency signs --- assets/config/cfg.json | 2 +- src/atomic.dex.cfg.cpp | 2 ++ src/atomic.dex.cfg.hpp | 14 ++++++++------ src/atomic.dex.provider.coinpaprika.cpp | 4 +--- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/assets/config/cfg.json b/assets/config/cfg.json index 6dfe6222b9..5304032942 100644 --- a/assets/config/cfg.json +++ b/assets/config/cfg.json @@ -7,7 +7,7 @@ ], "current_currency": "USD", "current_fiat": "USD", - "current_sign": "$", + "current_currency_sign": "$", "available_signs": { "USD": "$", "EUR": "€", diff --git a/src/atomic.dex.cfg.cpp b/src/atomic.dex.cfg.cpp index 60f889a0fd..9768547ce2 100644 --- a/src/atomic.dex.cfg.cpp +++ b/src/atomic.dex.cfg.cpp @@ -52,6 +52,8 @@ namespace atomic_dex j.at("current_fiat").get_to(config.current_fiat); j.at("available_fiat").get_to(config.available_fiat); j.at("possible_currencies").get_to(config.possible_currencies); + j.at("current_currency_sign").get_to(config.current_currency_sign); + j.at("available_signs").get_to(config.available_currency_signs); } void diff --git a/src/atomic.dex.cfg.hpp b/src/atomic.dex.cfg.hpp index 926a1d36d6..3e7a240a96 100644 --- a/src/atomic.dex.cfg.hpp +++ b/src/atomic.dex.cfg.hpp @@ -22,12 +22,14 @@ namespace atomic_dex { struct cfg { - std::string current_lang{"en"}; - std::string current_currency; - std::string current_fiat; - std::vector available_lang; - std::vector available_fiat; - std::array possible_currencies; + std::string current_lang{"en"}; + std::string current_currency; + std::string current_fiat; + std::string current_currency_sign; + std::unordered_map available_currency_signs; + std::vector available_lang; + std::vector available_fiat; + std::array possible_currencies; }; void from_json(const nlohmann::json& j, cfg& config); diff --git a/src/atomic.dex.provider.coinpaprika.cpp b/src/atomic.dex.provider.coinpaprika.cpp index de10301787..ab7e5f07d3 100644 --- a/src/atomic.dex.provider.coinpaprika.cpp +++ b/src/atomic.dex.provider.coinpaprika.cpp @@ -397,15 +397,13 @@ namespace atomic_dex } else { - //! Todo pickup from api open rates - if (m_usd_rate_providers.find(ticker) == m_usd_rate_providers.cend()) { ec = dextop_error::unknown_ticker_for_rate_conversion; return "0.00"; } t_float_50 tmp_current_price = t_float_50(m_usd_rate_providers.at(ticker)) * m_other_fiats_rates->at("rates").at(fiat).get(); - current_price = tmp_current_price.str(); + current_price = tmp_current_price.str(); } if (adjusted) From 23e91e1ee0211d27e960d2fb0ef9a9ec556f7a3d Mon Sep 17 00:00:00 2001 From: milerius Date: Sun, 2 Aug 2020 07:02:31 +0200 Subject: [PATCH 133/515] feat(high_dpi): specify the condition only for linux/osx --- main.cpp | 47 ++++++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/main.cpp b/main.cpp index 6969c648c4..e4b75193d3 100644 --- a/main.cpp +++ b/main.cpp @@ -1,9 +1,9 @@ #include #include -#include -#include #include +#include #include +#include #include #define QZXING_QML @@ -48,7 +48,7 @@ main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) #endif { // Determine if we pass through or floor - //SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); + // SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); std::signal(SIGABRT, signal_handler); //! Project @@ -87,26 +87,31 @@ main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) spdlog::info("Logger successfully initialized"); bool should_floor = false; +#if defined(_WIN32) || defined(WIN32) || defined(__linux__) + { + int ac = 0; + QApplication tmp(ac, nullptr); + double min_window_size = 800.0; + auto screens = tmp.screens(); + for (auto&& cur_screen: screens) { - int ac = 0; - QApplication tmp(ac, nullptr); - double min_window_size = 800.0; - auto screens = tmp.screens(); - for (auto&& cur_screen : screens) { - spdlog::trace("physical dpi: {}", cur_screen->physicalDotsPerInch()); - spdlog::trace("logical dpi: {}", cur_screen->logicalDotsPerInch()); - double scale = cur_screen->logicalDotsPerInch() / 96.0; - spdlog::trace("scale: {}", scale); - - double height = cur_screen->availableSize().height(); - spdlog::trace("height: {}", height); - if (scale * min_window_size > height) { - should_floor = true; - spdlog::trace("should floor"); - } + spdlog::trace("physical dpi: {}", cur_screen->physicalDotsPerInch()); + spdlog::trace("logical dpi: {}", cur_screen->logicalDotsPerInch()); + double scale = cur_screen->logicalDotsPerInch() / 96.0; + spdlog::trace("scale: {}", scale); + + double height = cur_screen->availableSize().height(); + spdlog::trace("height: {}", height); + if (scale * min_window_size > height) + { + should_floor = true; + spdlog::trace("should floor"); } } - QGuiApplication::setHighDpiScaleFactorRoundingPolicy(should_floor ? Qt::HighDpiScaleFactorRoundingPolicy::Floor : Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); + } +#endif + QGuiApplication::setHighDpiScaleFactorRoundingPolicy( + should_floor ? Qt::HighDpiScaleFactorRoundingPolicy::Floor : Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); QGuiApplication::setAttribute(should_floor ? Qt::AA_DisableHighDpiScaling : Qt::AA_EnableHighDpiScaling); //! App declaration atomic_dex::application atomic_app; @@ -114,7 +119,7 @@ main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) //! QT int ac = 0; std::shared_ptr app = std::make_shared(ac, nullptr); - + atomic_app.set_qt_app(app); //! QT QML From 9c556b13ac1845f8334ab213d073fe5190d5f386 Mon Sep 17 00:00:00 2001 From: naezith Date: Sun, 2 Aug 2020 16:43:39 +0300 Subject: [PATCH 134/515] feat(gui): dex layout rework --- .../qml/Exchange/Trade/PriceLine.qml | 13 +++--- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 45 ++++++++++--------- 2 files changed, 33 insertions(+), 25 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/PriceLine.qml b/atomic_qt_design/qml/Exchange/Trade/PriceLine.qml index cbf64cd09a..e1a0ed0212 100644 --- a/atomic_qt_design/qml/Exchange/Trade/PriceLine.qml +++ b/atomic_qt_design/qml/Exchange/Trade/PriceLine.qml @@ -11,8 +11,8 @@ RowLayout { readonly property bool invalid_cex_price: parseFloat(cex_price) === 0 readonly property double price_diff: invalid_cex_price ? 0 : 100 * (1 - parseFloat(price) / parseFloat(cex_price)) - readonly property int fontSize: Style.textSizeSmall2 - readonly property int fontSizeBigger: Style.textSizeSmall4 + readonly property int fontSize: Style.textSizeSmall1 + readonly property int fontSizeBigger: Style.textSizeSmall2 readonly property int line_scale: getComparisonScale(price_diff) readonly property bool price_entered: hasValidPrice() @@ -25,8 +25,6 @@ RowLayout { return parseFloat(value.toFixed(2)) } - spacing: 100 - DefaultText { visible: !price_entered && invalid_cex_price Layout.alignment: Qt.AlignHCenter @@ -37,6 +35,7 @@ RowLayout { ColumnLayout { visible: price_entered + Layout.alignment: Qt.AlignHCenter DefaultText { Layout.alignment: Qt.AlignHCenter @@ -64,6 +63,7 @@ RowLayout { // Price Comparison ColumnLayout { visible: price_entered && !invalid_cex_price + Layout.alignment: Qt.AlignHCenter DefaultText { id: price_diff_text @@ -76,13 +76,14 @@ RowLayout { } RowLayout { + Layout.alignment: Qt.AlignHCenter DefaultText { text_value: API.get().empty_string + (General.formatPercent(line_scale)) font.pixelSize: fontSize } GradientRectangle { - width: 200 + width: 125 height: 6 start_color: Style.colorGreen @@ -111,6 +112,8 @@ RowLayout { // CEXchange ColumnLayout { visible: !invalid_cex_price + Layout.alignment: Qt.AlignHCenter + DefaultText { Layout.alignment: Qt.AlignHCenter text_value: API.get().empty_string + (General.cex_icon + " " + qsTr("CEXchange rate")) diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index ec50c177f0..d1f801a7c8 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -362,12 +362,27 @@ Item { anchors.bottom: parent.bottom anchors.rightMargin: layout_margin + InnerBackground { + id: graph_bg + + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: selectors.top + anchors.bottomMargin: layout_margin * 2 + + CandleStickChart { + anchors.fill: parent + } + } + // Ticker Selectors RowLayout { id: selectors anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top + anchors.bottom: orderbook.top + anchors.bottomMargin: layout_margin spacing: 40 TickerSelector { @@ -390,24 +405,19 @@ Item { } } - InnerBackground { - id: graph_bg - + Orderbook { + id: orderbook + height: 250 anchors.left: parent.left anchors.right: parent.right - anchors.top: selectors.bottom - anchors.topMargin: layout_margin - anchors.bottom: orderbook.top - anchors.bottomMargin: layout_margin * 2 - - CandleStickChart { - anchors.fill: parent - } + anchors.bottom: price_line.top + anchors.bottomMargin: layout_margin } - Orderbook { - id: orderbook - height: 250 + + // Price + PriceLine { + id: price_line anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom @@ -472,11 +482,6 @@ Item { } } - // Price - PriceLine { - Layout.alignment: Qt.AlignHCenter - } - ConfirmTradeModal { id: confirm_trade_modal } From 847b11994d078c0f92bf6523c60d264ba282a18e Mon Sep 17 00:00:00 2001 From: naezith Date: Sun, 2 Aug 2020 19:27:21 +0300 Subject: [PATCH 135/515] feat(gui): proper price comparison for buy side --- atomic_qt_design/qml/Exchange/Trade/PriceLine.qml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/PriceLine.qml b/atomic_qt_design/qml/Exchange/Trade/PriceLine.qml index e1a0ed0212..3058b77736 100644 --- a/atomic_qt_design/qml/Exchange/Trade/PriceLine.qml +++ b/atomic_qt_design/qml/Exchange/Trade/PriceLine.qml @@ -9,7 +9,8 @@ import "../../Constants" RowLayout { readonly property double price: !orderIsSelected() ? getCalculatedPrice() : preffered_order.price readonly property bool invalid_cex_price: parseFloat(cex_price) === 0 - readonly property double price_diff: invalid_cex_price ? 0 : 100 * (1 - parseFloat(price) / parseFloat(cex_price)) + readonly property double price_diff: invalid_cex_price ? 0 : 100 * (1 - parseFloat(price) / parseFloat(cex_price)) * + (sell_mode ? 1 : -1) readonly property int fontSize: Style.textSizeSmall1 readonly property int fontSizeBigger: Style.textSizeSmall2 From 9e0e3d466c0b0420c9583632b37a1b701af9e304 Mon Sep 17 00:00:00 2001 From: naezith Date: Sun, 2 Aug 2020 22:34:51 +0300 Subject: [PATCH 136/515] feat(gui): place buy order --- .../qml/Exchange/Trade/OrderForm.qml | 21 +++++++------ atomic_qt_design/qml/Exchange/Trade/Trade.qml | 31 ++++++++++--------- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index 830ef64f1f..8a1b115139 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -75,22 +75,19 @@ FloatingBackground { return General.isEthEnabled() && API.get().do_i_have_enough_funds("ETH", curr_trade_info.erc_fees) } - function higherThanMinTradeAmount() { - return input_volume.field.text !== '' && parseFloat(input_volume.field.text) >= General.getMinTradeAmount() + function higherThanMinTradeAmount(is_base) { + if(input_volume.field.text === '') return false + return parseFloat(is_base ? input_volume.field.text : total_amount) >= General.getMinTradeAmount() } function isValid() { let valid = true - // Both sides if(valid) valid = fieldsAreFilled() if(valid) valid = higherThanMinTradeAmount() - if(!my_side) return valid - - // Sell side if(valid) valid = !notEnoughBalance() - if(valid) valid = API.get().do_i_have_enough_funds(getTicker(my_side), input_volume.field.text) + if(valid) valid = API.get().do_i_have_enough_funds(getTicker(my_side), General.formatDouble(getNeededAmountToSpend(input_volume.field.text))) if(valid && hasEthFees()) valid = hasEnoughEthForFees() return valid @@ -139,12 +136,18 @@ FloatingBackground { return false } + function getNeededAmountToSpend(volume) { + volume = parseFloat(volume) + if(my_side) return volume + else return volume * parseFloat(getCurrentPrice()) + } + function notEnoughBalance() { - return my_side && parseFloat(getMaxVolume()) < General.getMinTradeAmount() + return getNeededAmountToSpend(getMaxVolume()) < General.getMinTradeAmount() } function shouldBlockInput() { - return my_side && (notEnoughBalance() || notEnoughBalanceForFees()) + return notEnoughBalance() || notEnoughBalanceForFees() } function onInputChanged() { diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index d1f801a7c8..d43530c5ca 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -76,18 +76,12 @@ Item { form_base.updateRelAmount(true) form_rel.updateRelAmount(true) - form_base.field.forceActiveFocus() + getCurrentForm().field.forceActiveFocus() } function getCalculatedPrice() { - if(sell_mode) { - let sell_price = form_base.price_field.text - return General.isZero(sell_price) ? "0" : sell_price - } - else { - let buy_price = form_rel.price_field.text - return General.isZero(buy_price) ? "0" : buy_price - } + let price = getCurrentForm().price_field.text + return General.isZero(price) ? "0" : price } function getCurrentPrice() { @@ -125,7 +119,7 @@ Item { } function notEnoughBalance() { - return form_base.notEnoughBalance() + return getCurrentForm().notEnoughBalance() } @@ -282,16 +276,23 @@ Item { function trade(base, rel) { updateTradeInfo(true) // Force update trade info and cap the value for one last time + const current_form = getCurrentForm() + const is_created_order = !orderIsSelected() const price_denom = preffered_order.price_denom const price_numer = preffered_order.price_numer const price = getCurrentPrice() - const volume = form_base.field.text - console.log("QML place_sell_order: max balance:", form_base.getMaxVolume()) - console.log("QML place_sell_order: params:", base, " <-> ", rel, " / price:", price, " / volume:", volume, " / is_created_order:", is_created_order, " / price_denom:", price_denom, " / price_numer:", price_numer) - console.log("QML place_sell_order: trade info:", JSON.stringify(curr_trade_info)) + const volume = current_form.field.text + console.log("QML place order: max balance:", current_form.getMaxVolume()) + console.log("QML place order: params:", base, " <-> ", rel, " / price:", price, " / volume:", volume, " / is_created_order:", is_created_order, " / price_denom:", price_denom, " / price_numer:", price_numer) + console.log("QML place order: trade info:", JSON.stringify(curr_trade_info)) + + let result - const result = API.get().place_sell_order(base, rel, price, volume, is_created_order, price_denom, price_numer) + if(sell_mode) + result = API.get().place_sell_order(base, rel, price, volume, is_created_order, price_denom, price_numer) + else + result = API.get().place_buy_order(base, rel, price, volume, is_created_order, price_denom, price_numer) if(result === "") { action_result = "success" From bde30c8baaf8b7928ea7c5a26f3b424f66f38c38 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Sun, 2 Aug 2020 21:50:41 +0200 Subject: [PATCH 137/515] feat(orders): good base/rel for taker order + action Signed-off-by: romanszterg --- src/atomic.dex.mm2.api.cpp | 8 +++++++- src/atomic.dex.mm2.api.hpp | 1 + src/atomic.dex.qt.orders.model.cpp | 21 +++++++++++++-------- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/atomic.dex.mm2.api.cpp b/src/atomic.dex.mm2.api.cpp index 97baf8ef57..471f60c07d 100644 --- a/src/atomic.dex.mm2.api.cpp +++ b/src/atomic.dex.mm2.api.cpp @@ -653,6 +653,11 @@ namespace mm2::api const auto time_key = value.at("created_at").get(); sys_time tp{std::chrono::milliseconds{time_key}}; auto tp_zoned = date::make_zoned(current_zone(), tp); + std::string action = "Buy"; + if (not is_maker) + { + value.at("request").at("action").get_to(action); + } my_order_contents contents{ .order_id = key, .price = is_maker ? adjust_precision(value.at("price").get()) : "0", @@ -663,7 +668,8 @@ namespace mm2::api .order_type = is_maker ? "maker" : "taker", .base_amount = is_maker ? value.at("max_base_vol").get() : value.at("request").at("base_amount").get(), .rel_amount = is_maker ? (t_float_50(contents.price) * t_float_50(contents.base_amount)).convert_to() : value.at("request").at("rel_amount").get(), - .human_timestamp = date::format("%F %T", tp_zoned)}; + .human_timestamp = date::format("%F %T", tp_zoned), + .action = action}; out.try_emplace(time_key, std::move(contents)); }; // clang-format on diff --git a/src/atomic.dex.mm2.api.hpp b/src/atomic.dex.mm2.api.hpp index ac56ef8719..59c2703f82 100644 --- a/src/atomic.dex.mm2.api.hpp +++ b/src/atomic.dex.mm2.api.hpp @@ -582,6 +582,7 @@ namespace mm2::api std::string base_amount; std::string rel_amount; std::string human_timestamp; + std::string action; }; struct my_orders_answer diff --git a/src/atomic.dex.qt.orders.model.cpp b/src/atomic.dex.qt.orders.model.cpp index 78207add25..516d18b44f 100644 --- a/src/atomic.dex.qt.orders.model.cpp +++ b/src/atomic.dex.qt.orders.model.cpp @@ -313,7 +313,8 @@ namespace atomic_dex data.order_error_state = error.first; data.order_error_message = error.second; } - if (this->m_swaps_id_registry.find(contents.uuid) == m_swaps_id_registry.end()) { + if (this->m_swaps_id_registry.find(contents.uuid) == m_swaps_id_registry.end()) + { this->m_swaps_id_registry.emplace(contents.uuid); } this->m_model_data.push_back(std::move(data)); @@ -341,9 +342,13 @@ namespace atomic_dex update_value(OrdersRoles::OrderErrorStateRole, state, idx, *this); update_value(OrdersRoles::OrderErrorMessageRole, msg, idx, *this); emit lengthChanged(); - } else { - bool is_maker = boost::algorithm::to_lower_copy(contents.type) == "maker"; - spdlog::error("swap with id {} and ticker: {}, not found in the model, cannot update, forcing an initialization instead", contents.uuid, is_maker ? contents.maker_coin : contents.taker_coin); + } + else + { + bool is_maker = boost::algorithm::to_lower_copy(contents.type) == "maker"; + spdlog::error( + "swap with id {} and ticker: {}, not found in the model, cannot update, forcing an initialization instead", contents.uuid, + is_maker ? contents.maker_coin : contents.taker_coin); initialize_swap(contents); } } @@ -355,10 +360,10 @@ namespace atomic_dex beginInsertRows(QModelIndex(), this->m_model_data.count(), this->m_model_data.count()); order_data data{ .is_maker = contents.order_type == "maker", - .base_coin = QString::fromStdString(contents.base), - .rel_coin = QString::fromStdString(contents.rel), - .base_amount = QString::fromStdString(contents.base_amount), - .rel_amount = QString::fromStdString(contents.rel_amount), + .base_coin = contents.action == "Sell" ? QString::fromStdString(contents.base) : QString::fromStdString(contents.rel), + .rel_coin = contents.action == "Sell" ? QString::fromStdString(contents.rel) : QString::fromStdString(contents.base), + .base_amount = contents.action == "Sell" ? QString::fromStdString(contents.base_amount) : QString::fromStdString(contents.rel_amount), + .rel_amount = contents.action == "Sell" ? QString::fromStdString(contents.rel_amount) : QString::fromStdString(contents.base_amount), .order_type = QString::fromStdString(contents.order_type), .human_date = QString::fromStdString(contents.human_timestamp), .unix_timestamp = static_cast(contents.timestamp), From 200fa136df196ac3e3fce7b5c02210420f665235 Mon Sep 17 00:00:00 2001 From: naezith Date: Sun, 2 Aug 2020 23:20:16 +0300 Subject: [PATCH 138/515] feat(gui): fix trade form was being blocked --- atomic_qt_design/qml/Exchange/Trade/OrderForm.qml | 5 +++++ atomic_qt_design/qml/Exchange/Trade/Trade.qml | 14 ++++---------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index 8a1b115139..bde999f546 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -143,6 +143,11 @@ FloatingBackground { } function notEnoughBalance() { + // If sell side or buy side but there is no price, then just check the balance + if(my_side || General.isZero(getCurrentPrice())) + return parseFloat(getMaxVolume()) < General.getMinTradeAmount() + + // If it's buy, and price exists then multiply and check return getNeededAmountToSpend(getMaxVolume()) < General.getMinTradeAmount() } diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index d43530c5ca..eec4e2806e 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -125,13 +125,6 @@ Item { function getTradeInfo(base, rel, amount, set_as_current=true) { if(inCurrentPage()) { - // Swap the trade info because of buy / sell, amount is already correct - if(!sell_mode) { - const tmp = base - base = rel - rel = tmp - } - let info = API.get().get_trade_infos(base, rel, amount) console.log("Getting Trade info with parameters: ", base, rel, amount, " - Result: ", JSON.stringify(info)) @@ -160,9 +153,10 @@ Item { } function updateTradeInfo(force=false) { - const base = getTicker(true) - const rel = getTicker(false) - const amount = getCurrentForm().getVolume() + const base = getTicker(sell_mode) + const rel = getTicker(!sell_mode) + const amount = sell_mode ? getCurrentForm().getVolume() : + General.formatDouble(getCurrentForm().getNeededAmountToSpend(getCurrentForm().getVolume())) if(force || (base !== undefined && rel !== undefined && amount !== undefined && base !== '' && rel !== '' && amount !== '' && amount !== '0')) { From 074d0166f0022393e6bd059dc779dbbf7bf0fa9a Mon Sep 17 00:00:00 2001 From: naezith Date: Mon, 3 Aug 2020 00:34:19 +0300 Subject: [PATCH 139/515] feat(gui): cap buy volume --- .../qml/Exchange/Trade/OrderForm.qml | 31 ++++++++++++++----- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 10 ------ 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index bde999f546..36b96639cb 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -100,11 +100,20 @@ FloatingBackground { function getMaxTradableVolume(set_as_current) { // set_as_current should be true if input_volume is updated // if it's called for cap check, it should be false because that's not the current input_volume - return getSendAmountAfterFees(getMaxVolume(), set_as_current) - } - function setMax() { - input_volume.field.text = getMaxTradableVolume(true) + const base = getTicker(sell_mode) + const rel = getTicker(!sell_mode) + const amount = getMaxVolume() + + if(base === '' || rel === '') return 0 + + const info = getTradeInfo(base, rel, amount, set_as_current) + const my_amt = parseFloat(valid_trade_info ? info.input_final_value : amount) + if(my_side) return my_amt + + // If it's buy side, then volume input needs to be calculated with the current price + const price = parseFloat(getCurrentPrice()) + return price === 0 ? 0 : my_amt / price } function reset(is_base) { @@ -116,7 +125,8 @@ FloatingBackground { // We don't want to reset base balance at rel ticker change // Therefore it will reset only if this info is set from ComboBox -> setPair // Or if it's from somewhere else like page change, in that case is_base is undefined - if(is_base === undefined || is_base) setMax() + if(is_base === undefined || is_base) + input_volume.field.text = getMaxTradableVolume(true) } else { input_volume.field.text = '' @@ -124,7 +134,11 @@ FloatingBackground { } function capVolume() { - if(inCurrentPage() && my_side && input_volume.field.acceptableInput) { + if(inCurrentPage() && input_volume.field.acceptableInput) { + // If price is 0 at buy side, don't cap it to 0, let the user edit + if(!my_side && General.isZero(getCurrentPrice())) + return false + const amt = parseFloat(input_volume.field.text) const cap_with_fees = getMaxTradableVolume(false) if(amt > cap_with_fees) { @@ -144,8 +158,9 @@ FloatingBackground { function notEnoughBalance() { // If sell side or buy side but there is no price, then just check the balance - if(my_side || General.isZero(getCurrentPrice())) + if(my_side || General.isZero(getCurrentPrice())) { return parseFloat(getMaxVolume()) < General.getMinTradeAmount() + } // If it's buy, and price exists then multiply and check return getNeededAmountToSpend(getMaxVolume()) < General.getMinTradeAmount() @@ -215,7 +230,7 @@ FloatingBackground { Layout.rightMargin: top_line.Layout.rightMargin Layout.bottomMargin: -6 Layout.fillWidth: true - field.enabled: root.enabled && !shouldBlockInput() + enabled: input_volume.field.enabled field.left_text: API.get().empty_string + (qsTr("Price")) field.right_text: getTicker(false) diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index eec4e2806e..5fe000492e 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -302,16 +302,6 @@ Item { } } - function getSendAmountAfterFees(amount, set_as_current) { - const base = getTicker(true) - const rel = getTicker(false) - - if(base === '' || rel === '') return 0 - - const info = getTradeInfo(getTicker(true), getTicker(false), amount, set_as_current) - return parseFloat(valid_trade_info ? info.input_final_value : amount) - } - // No coins warning ColumnLayout { anchors.centerIn: parent From b142b1dace01f5354972e4fd2c441eef638956e1 Mon Sep 17 00:00:00 2001 From: naezith Date: Mon, 3 Aug 2020 01:36:29 +0300 Subject: [PATCH 140/515] feat(gui): cap volume with order volume and user balance limits --- .../qml/Exchange/Trade/OrderForm.qml | 32 ++++++------------- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 14 +++++--- 2 files changed, 19 insertions(+), 27 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index 36b96639cb..357d1c4492 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -16,7 +16,7 @@ FloatingBackground { property alias column_layout: form_layout property string total_amount: "0" - function updateRelAmount(set_order_volume) { + function updateRelAmount() { const price = parseFloat(getCurrentPrice()) const base_volume = parseFloat(getVolume()) let new_receive = base_volume * price @@ -26,27 +26,15 @@ FloatingBackground { const selected_order = preffered_order // Cap the volume with the order volume const order_buy_volume = parseFloat(selected_order.volume) - if(set_order_volume || parseFloat(getVolume()) > order_buy_volume) { - const new_sell_volume = General.formatDouble(order_buy_volume) - input_volume.field.text = new_sell_volume + if(my_side) { + if(parseFloat(getVolume()) > order_buy_volume) { + const new_sell_volume = General.formatDouble(order_buy_volume) + input_volume.field.text = new_sell_volume - // Calculate new receive amount - new_receive = order_buy_volume * price + // Calculate new receive amount + new_receive = order_buy_volume * price + } } - -// // If new rel volume is higher than the order max volume -// const max_rel_volume = parseFloat(selected_order.volume) -// if(new_receive > max_rel_volume) { -// new_receive = max_rel_volume - -// // Set base depending on the capped rel -// const max_base_volume = max_rel_volume / price -// if(base_volume !== max_base_volume) { -// const new_base_text = General.formatDouble(max_base_volume) -// if(input_volume.field.text !== new_base_text) -// input_volume.field.text = new_base_text -// } -// } } // Set rel @@ -126,7 +114,7 @@ FloatingBackground { // Therefore it will reset only if this info is set from ComboBox -> setPair // Or if it's from somewhere else like page change, in that case is_base is undefined if(is_base === undefined || is_base) - input_volume.field.text = getMaxTradableVolume(true) + input_volume.field.text = General.formatDouble(getMaxTradableVolume(true)) } else { input_volume.field.text = '' @@ -142,7 +130,7 @@ FloatingBackground { const amt = parseFloat(input_volume.field.text) const cap_with_fees = getMaxTradableVolume(false) if(amt > cap_with_fees) { - input_volume.field.text = cap_with_fees.toString() + input_volume.field.text = General.formatDouble(cap_with_fees.toString()) return true } } diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index 5fe000492e..a343d9699b 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -69,12 +69,16 @@ Item { preffered_order.price_numer = price_numer preffered_order = preffered_order + const volume_text = General.formatDouble(quantity) const price_text = General.formatDouble(price) - form_base.price_field.text = price_text - form_rel.price_field.text = price_text - - form_base.updateRelAmount(true) - form_rel.updateRelAmount(true) + if(is_asks) { + form_rel.field.text = volume_text + form_rel.price_field.text = price_text + } + else { + form_base.field.text = volume_text + form_base.price_field.text = price_text + } getCurrentForm().field.forceActiveFocus() } From 2dbb7c7b95b14591cb50b8cfa5b5b0412ae62302 Mon Sep 17 00:00:00 2001 From: naezith Date: Mon, 3 Aug 2020 01:49:57 +0300 Subject: [PATCH 141/515] feat(gui): better capping and volume precision --- .../qml/Exchange/Trade/OrderForm.qml | 55 ++++++++----------- 1 file changed, 23 insertions(+), 32 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index 357d1c4492..8a1beeec89 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -16,33 +16,6 @@ FloatingBackground { property alias column_layout: form_layout property string total_amount: "0" - function updateRelAmount() { - const price = parseFloat(getCurrentPrice()) - const base_volume = parseFloat(getVolume()) - let new_receive = base_volume * price - - // If an order is selected - if(orderIsSelected()) { - const selected_order = preffered_order - // Cap the volume with the order volume - const order_buy_volume = parseFloat(selected_order.volume) - if(my_side) { - if(parseFloat(getVolume()) > order_buy_volume) { - const new_sell_volume = General.formatDouble(order_buy_volume) - input_volume.field.text = new_sell_volume - - // Calculate new receive amount - new_receive = order_buy_volume * price - } - } - } - - // Set rel - const new_receive_text = General.formatDouble(new_receive) - if(total_amount !== new_receive_text) - total_amount = new_receive_text - } - function getFiatText(v, ticker) { return General.formatFiat('', v === '' ? 0 : API.get().get_fiat_from_amount(ticker, v), API.get().current_fiat) + " " + General.cex_icon } @@ -127,10 +100,24 @@ FloatingBackground { if(!my_side && General.isZero(getCurrentPrice())) return false - const amt = parseFloat(input_volume.field.text) + const input_volume_value = parseFloat(input_volume.field.text) + let amt = input_volume_value + + // Cap with balance const cap_with_fees = getMaxTradableVolume(false) - if(amt > cap_with_fees) { - input_volume.field.text = General.formatDouble(cap_with_fees.toString()) + if(amt > cap_with_fees) + amt = cap_with_fees + + // Cap with order volume + if(orderIsSelected()) { + const order_buy_volume = parseFloat(preffered_order.volume) + if(amt > order_buy_volume) + amt = order_buy_volume + } + + // Set the field + if(amt !== input_volume_value) { + input_volume.field.text = General.formatDouble(amt) return true } } @@ -161,8 +148,12 @@ FloatingBackground { function onInputChanged() { if(capVolume()) updateTradeInfo() - // Rel is dependant on Base if price is set so update that - updateRelAmount() + // Recalculate total amount + const price = parseFloat(getCurrentPrice()) + const base_volume = parseFloat(getVolume()) + const new_receive_text = General.formatDouble(base_volume * price) + if(total_amount !== new_receive_text) + total_amount = new_receive_text // Update the new fees, input_volume might be changed updateTradeInfo() From 87d9a25c174772504967b21e4717a3a187cd60cc Mon Sep 17 00:00:00 2001 From: naezith Date: Mon, 3 Aug 2020 02:00:52 +0300 Subject: [PATCH 142/515] feat(gui): implement new buy/sell warning messages --- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index a343d9699b..279d4bce18 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -455,18 +455,16 @@ Item { color: Style.colorRed text_value: API.get().empty_string + ( - notEnoughBalance() ? (qsTr("%1 balance is lower than minimum trade amount").arg(selector_base.getTicker()) + " : " + General.getMinTradeAmount()) : - notEnoughBalanceForFees() ? - (qsTr("Not enough balance for the fees. Need at least %1 more", "AMT TICKER").arg(General.formatCrypto("", parseFloat(curr_trade_info.amount_needed), selector_base.getTicker()))) : - (form_base.hasEthFees() && !form_base.hasEnoughEthForFees()) ? (qsTr("Not enough ETH for the transaction fee")) : - (form_base.fieldsAreFilled() && !form_base.higherThanMinTradeAmount()) ? (qsTr("Sell amount is lower than minimum trade amount") + " : " + General.getMinTradeAmount()) : - (form_rel.fieldsAreFilled() && !form_rel.higherThanMinTradeAmount()) ? (qsTr("Receive amount is lower than minimum trade amount") + " : " + General.getMinTradeAmount()) : "" - + General.isZero(getCurrentPrice()) ? (qsTr("Please fill the price field")) : + notEnoughBalance() ? (qsTr("%1 balance is lower than minimum trade amount").arg(getTicker(sell_mode)) + " : " + General.getMinTradeAmount()) : + notEnoughBalanceForFees() ? + (qsTr("Not enough balance for the fees. Need at least %1 more", "AMT TICKER").arg(General.formatCrypto("", parseFloat(curr_trade_info.amount_needed), getTicker(sell_mode)))) : + General.isZero(getCurrentForm().getVolume()) ? (qsTr("Please fill the volume field")) : + (getCurrentForm().hasEthFees() && !getCurrentForm().hasEnoughEthForFees()) ? (qsTr("Not enough ETH for the transaction fee")) : + (getCurrentForm().fieldsAreFilled() && !getCurrentForm().higherThanMinTradeAmount()) ? ((qsTr("Amount is lower than minimum trade amount")) + " : " + General.getMinTradeAmount()) : "" ) - visible: form_base.fieldsAreFilled() && (notEnoughBalanceForFees() || - (form_base.hasEthFees() && !form_base.hasEnoughEthForFees()) || - !form_base.higherThanMinTradeAmount() || - (form_rel.fieldsAreFilled() && !form_rel.higherThanMinTradeAmount())) + + visible: text_value !== "" } } } From adcb3ec2a36e87c40305491cec91669878e2d89c Mon Sep 17 00:00:00 2001 From: romanszterg Date: Mon, 3 Aug 2020 10:35:49 +0200 Subject: [PATCH 143/515] feat(multiple_currencies): change currency sign in backend Signed-off-by: romanszterg --- src/atomic.dex.cfg.cpp | 15 ++++++++++++++- src/atomic.dex.cfg.hpp | 1 + 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/atomic.dex.cfg.cpp b/src/atomic.dex.cfg.cpp index 9768547ce2..f00da869b9 100644 --- a/src/atomic.dex.cfg.cpp +++ b/src/atomic.dex.cfg.cpp @@ -94,6 +94,7 @@ namespace atomic_dex { spdlog::info("{} is fiat, setting it as current fiat and possible currencies", new_currency); config.current_fiat = new_currency; + config.current_currency_sign = retrieve_sign_from_ticker(config, new_currency); config.possible_currencies[0] = new_currency; } upgrade_cfg(config); @@ -102,8 +103,20 @@ namespace atomic_dex void change_fiat(cfg& config, const std::string& new_fiat) { - config.current_fiat = new_fiat; + config.current_fiat = new_fiat; config.possible_currencies[0] = new_fiat; upgrade_cfg(config); } + + std::string + retrieve_sign_from_ticker(const cfg& config, const std::string& currency) noexcept + { +#if defined(__linux__) + if (currency == "BTC") + { + return config.available_currency_signs.at("BTC_ALT"); + } +#endif + return config.available_currency_signs.at(currency); + } } // namespace atomic_dex diff --git a/src/atomic.dex.cfg.hpp b/src/atomic.dex.cfg.hpp index 3e7a240a96..a1b0d3ea8e 100644 --- a/src/atomic.dex.cfg.hpp +++ b/src/atomic.dex.cfg.hpp @@ -38,4 +38,5 @@ namespace atomic_dex void change_fiat(cfg& config, const std::string& new_fiat); [[nodiscard]] bool is_this_currency_a_fiat(cfg& config, const std::string& currency) noexcept; cfg load_cfg(); + std::string retrieve_sign_from_ticker(const cfg& config, const std::string& currency) noexcept; } // namespace atomic_dex \ No newline at end of file From 708b4cee507cc0d4d5ce33d87fb735908d103295 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Mon, 3 Aug 2020 10:42:47 +0200 Subject: [PATCH 144/515] feat(currency_sign): add property Signed-off-by: romanszterg --- src/atomic.dex.app.cpp | 7 +++++++ src/atomic.dex.app.hpp | 3 +++ 2 files changed, 10 insertions(+) diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index 011e461863..187cb8f463 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -500,6 +500,12 @@ namespace atomic_dex this->m_portfolio->initialize_portfolio(evt.ticker); } + QString + application::get_current_currency_sign() const noexcept + { + return QString::fromStdString(this->m_config.current_currency_sign); + } + QString application::get_current_currency() const noexcept { @@ -515,6 +521,7 @@ namespace atomic_dex atomic_dex::change_currency(m_config, current_currency.toStdString()); this->m_portfolio->update_currency_values(); emit on_currency_changed(); + emit on_currency_sign_changed(); } } diff --git a/src/atomic.dex.app.hpp b/src/atomic.dex.app.hpp index b538fdd596..c98bbf56ad 100644 --- a/src/atomic.dex.app.hpp +++ b/src/atomic.dex.app.hpp @@ -63,6 +63,7 @@ namespace atomic_dex Q_PROPERTY(QVariant update_status READ get_update_status NOTIFY updateStatusChanged) Q_PROPERTY(portfolio_model* portfolio_mdl READ get_portfolio NOTIFY portfolioChanged) Q_PROPERTY(QString current_currency READ get_current_currency WRITE set_current_currency NOTIFY on_currency_changed) + Q_PROPERTY(QString current_currency_sign READ get_current_currency_sign NOTIFY on_currency_sign_changed) Q_PROPERTY(QString current_fiat READ get_current_fiat WRITE set_current_fiat NOTIFY on_fiat_changed) Q_PROPERTY(QString lang READ get_current_lang WRITE set_current_lang NOTIFY on_lang_changed) Q_PROPERTY(QString wallet_default_name READ get_wallet_default_name WRITE set_wallet_default_name NOTIFY on_wallet_default_name_changed) @@ -130,6 +131,7 @@ namespace atomic_dex QVariantList get_enabled_coins() const noexcept; QVariantList get_enableable_coins() const noexcept; QString get_current_currency() const noexcept; + QString get_current_currency_sign() const noexcept;; QString get_current_fiat() const noexcept; QString get_current_lang() const noexcept; QString get_balance_fiat_all() const noexcept; @@ -230,6 +232,7 @@ namespace atomic_dex void enableableCoinsChanged(); void coinInfoChanged(); void on_currency_changed(); + void on_currency_sign_changed(); void on_fiat_changed(); void on_second_fiat_changed(); void on_lang_changed(); From 079e38d8cec838e998463840c71256419a987e81 Mon Sep 17 00:00:00 2001 From: naezith Date: Mon, 3 Aug 2020 11:44:36 +0300 Subject: [PATCH 145/515] feat(gui): check 0. input at get trade info calls --- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index 279d4bce18..47f1a6de39 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -161,9 +161,7 @@ Item { const rel = getTicker(!sell_mode) const amount = sell_mode ? getCurrentForm().getVolume() : General.formatDouble(getCurrentForm().getNeededAmountToSpend(getCurrentForm().getVolume())) - if(force || - (base !== undefined && rel !== undefined && amount !== undefined && - base !== '' && rel !== '' && amount !== '' && amount !== '0')) { + if(force || (General.fieldExists(base) && General.fieldExists(rel) && !General.isZero(amount))) { getTradeInfo(base, rel, amount) // Since new implementation does not update fees instantly, re-cap the volume every time, just in case From 58e24ade6c6e6177e75e636f10de775e669923d7 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Mon, 3 Aug 2020 11:24:12 +0200 Subject: [PATCH 146/515] feat(currencies): update to json Signed-off-by: romanszterg --- src/atomic.dex.cfg.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/atomic.dex.cfg.cpp b/src/atomic.dex.cfg.cpp index f00da869b9..ebab008706 100644 --- a/src/atomic.dex.cfg.cpp +++ b/src/atomic.dex.cfg.cpp @@ -31,6 +31,8 @@ namespace config_json_data["current_currency"] = config.current_currency; config_json_data["current_fiat"] = config.current_fiat; config_json_data["possible_currencies"] = config.possible_currencies; + config_json_data["current_currency_sign"] = config.current_currency_sign; + config_json_data["available_signs"] = config.available_currency_signs; ifs.close(); From 2c374fda6741e32dc89b17df3913882db605fb48 Mon Sep 17 00:00:00 2001 From: naezith Date: Mon, 3 Aug 2020 12:37:59 +0300 Subject: [PATCH 147/515] feat(gui): use K M for large fiat values --- atomic_qt_design/qml/Constants/General.qml | 23 +++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/atomic_qt_design/qml/Constants/General.qml b/atomic_qt_design/qml/Constants/General.qml index b944068346..6b6810272b 100644 --- a/atomic_qt_design/qml/Constants/General.qml +++ b/atomic_qt_design/qml/Constants/General.qml @@ -97,6 +97,27 @@ QtObject { return data && data.rates && data.rates[fiat] } + function nFormatter(num, digits) { + if(num < 1E5) return num + + const si = [ + { value: 1, symbol: "" }, + { value: 1E3, symbol: "k" }, + { value: 1E6, symbol: "M" }, + { value: 1E9, symbol: "G" }, + { value: 1E12, symbol: "T" }, + { value: 1E15, symbol: "P" }, + { value: 1E18, symbol: "E" } + ] + const rx = /\.0+$|(\.[0-9]*[1-9])0+$/ + + let i + for (i = si.length - 1; i > 0; --i) + if (num >= si[i].value) break + + return (num / si[i].value).toFixed(digits).replace(rx, "$1") + si[i].symbol + } + function formatFiat(received, amount, fiat) { const symbols = { "USD": "$", @@ -105,7 +126,7 @@ QtObject { "KMD": "KMD", } - return diffPrefix(received) + symbols[fiat] + " " + amount + return diffPrefix(received) + symbols[fiat] + " " + nFormatter(parseFloat(amount), 2) } function formatPercent(value, show_prefix=true) { From 553022fe37fd76c3164d4be700f8beb8ae7facf8 Mon Sep 17 00:00:00 2001 From: milerius Date: Mon, 3 Aug 2020 11:55:53 +0200 Subject: [PATCH 148/515] feat(rates): fetch rates if it's was never fetched --- src/atomic.dex.provider.coinpaprika.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/atomic.dex.provider.coinpaprika.cpp b/src/atomic.dex.provider.coinpaprika.cpp index ab7e5f07d3..e38994b7d7 100644 --- a/src/atomic.dex.provider.coinpaprika.cpp +++ b/src/atomic.dex.provider.coinpaprika.cpp @@ -403,7 +403,7 @@ namespace atomic_dex return "0.00"; } t_float_50 tmp_current_price = t_float_50(m_usd_rate_providers.at(ticker)) * m_other_fiats_rates->at("rates").at(fiat).get(); - current_price = tmp_current_price.str(); + current_price = tmp_current_price.str(); } if (adjusted) @@ -433,6 +433,10 @@ namespace atomic_dex { spdlog::debug("{} l{} f[{}]", __FUNCTION__, __LINE__, fs::path(__FILE__).filename().string()); + if (not this->m_other_fiats_rates->contains("rates")) + { + this->m_other_fiats_rates = fetch_fiat_rates(); + } const auto config = m_mm2_instance.get_coin_info(evt.ticker); if (config.coinpaprika_id != "test-coin") From 12f8b512cda337c6cc667bb64ac991b3538d96f4 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Mon, 3 Aug 2020 12:17:16 +0200 Subject: [PATCH 149/515] feat(sign): add current fiat sign Signed-off-by: romanszterg --- assets/config/cfg.json | 1 + src/atomic.dex.app.cpp | 7 +++++++ src/atomic.dex.app.hpp | 5 ++++- src/atomic.dex.cfg.cpp | 17 ++++++++++------- src/atomic.dex.cfg.hpp | 1 + src/atomic.dex.provider.coinpaprika.cpp | 1 - 6 files changed, 23 insertions(+), 9 deletions(-) diff --git a/assets/config/cfg.json b/assets/config/cfg.json index 5304032942..6bec5b5a4e 100644 --- a/assets/config/cfg.json +++ b/assets/config/cfg.json @@ -8,6 +8,7 @@ "current_currency": "USD", "current_fiat": "USD", "current_currency_sign": "$", + "current_fiat_sign": "$", "available_signs": { "USD": "$", "EUR": "€", diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index 187cb8f463..8c9a795f9f 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -506,6 +506,12 @@ namespace atomic_dex return QString::fromStdString(this->m_config.current_currency_sign); } + QString + application::get_current_fiat_sign() const noexcept + { + return QString::fromStdString(this->m_config.current_fiat_sign); + } + QString application::get_current_currency() const noexcept { @@ -522,6 +528,7 @@ namespace atomic_dex this->m_portfolio->update_currency_values(); emit on_currency_changed(); emit on_currency_sign_changed(); + emit on_fiat_sign_changed(); } } diff --git a/src/atomic.dex.app.hpp b/src/atomic.dex.app.hpp index c98bbf56ad..b18015c7a0 100644 --- a/src/atomic.dex.app.hpp +++ b/src/atomic.dex.app.hpp @@ -64,6 +64,7 @@ namespace atomic_dex Q_PROPERTY(portfolio_model* portfolio_mdl READ get_portfolio NOTIFY portfolioChanged) Q_PROPERTY(QString current_currency READ get_current_currency WRITE set_current_currency NOTIFY on_currency_changed) Q_PROPERTY(QString current_currency_sign READ get_current_currency_sign NOTIFY on_currency_sign_changed) + Q_PROPERTY(QString current_fiat_sign READ get_current_fiat_sign NOTIFY on_fiat_sign_changed) Q_PROPERTY(QString current_fiat READ get_current_fiat WRITE set_current_fiat NOTIFY on_fiat_changed) Q_PROPERTY(QString lang READ get_current_lang WRITE set_current_lang NOTIFY on_lang_changed) Q_PROPERTY(QString wallet_default_name READ get_wallet_default_name WRITE set_wallet_default_name NOTIFY on_wallet_default_name_changed) @@ -131,7 +132,8 @@ namespace atomic_dex QVariantList get_enabled_coins() const noexcept; QVariantList get_enableable_coins() const noexcept; QString get_current_currency() const noexcept; - QString get_current_currency_sign() const noexcept;; + QString get_current_currency_sign() const noexcept; + QString get_current_fiat_sign() const noexcept;; QString get_current_fiat() const noexcept; QString get_current_lang() const noexcept; QString get_balance_fiat_all() const noexcept; @@ -233,6 +235,7 @@ namespace atomic_dex void coinInfoChanged(); void on_currency_changed(); void on_currency_sign_changed(); + void on_fiat_sign_changed(); void on_fiat_changed(); void on_second_fiat_changed(); void on_lang_changed(); diff --git a/src/atomic.dex.cfg.cpp b/src/atomic.dex.cfg.cpp index ebab008706..56ca15282a 100644 --- a/src/atomic.dex.cfg.cpp +++ b/src/atomic.dex.cfg.cpp @@ -27,12 +27,13 @@ namespace assert(ifs.is_open()); ifs >> config_json_data; - config_json_data["lang"] = config.current_lang; - config_json_data["current_currency"] = config.current_currency; - config_json_data["current_fiat"] = config.current_fiat; - config_json_data["possible_currencies"] = config.possible_currencies; + config_json_data["lang"] = config.current_lang; + config_json_data["current_currency"] = config.current_currency; + config_json_data["current_fiat"] = config.current_fiat; + config_json_data["possible_currencies"] = config.possible_currencies; config_json_data["current_currency_sign"] = config.current_currency_sign; - config_json_data["available_signs"] = config.available_currency_signs; + config_json_data["current_fiat_sign"] = config.current_fiat_sign; + config_json_data["available_signs"] = config.available_currency_signs; ifs.close(); @@ -56,6 +57,7 @@ namespace atomic_dex j.at("possible_currencies").get_to(config.possible_currencies); j.at("current_currency_sign").get_to(config.current_currency_sign); j.at("available_signs").get_to(config.available_currency_signs); + j.at("current_fiat_sign").get_to(config.current_fiat_sign); } void @@ -89,14 +91,15 @@ namespace atomic_dex void change_currency(cfg& config, const std::string& new_currency) { - config.current_currency = new_currency; + config.current_currency = new_currency; + config.current_currency_sign = retrieve_sign_from_ticker(config, new_currency); //! If it's fiat, i set the first element of the possible currencies to the new currency (the new fiat here) and i also set the current fiat if (is_this_currency_a_fiat(config, new_currency)) { spdlog::info("{} is fiat, setting it as current fiat and possible currencies", new_currency); config.current_fiat = new_currency; - config.current_currency_sign = retrieve_sign_from_ticker(config, new_currency); + config.current_fiat_sign = config.current_currency_sign; config.possible_currencies[0] = new_currency; } upgrade_cfg(config); diff --git a/src/atomic.dex.cfg.hpp b/src/atomic.dex.cfg.hpp index a1b0d3ea8e..0bb1dfe0cd 100644 --- a/src/atomic.dex.cfg.hpp +++ b/src/atomic.dex.cfg.hpp @@ -26,6 +26,7 @@ namespace atomic_dex std::string current_currency; std::string current_fiat; std::string current_currency_sign; + std::string current_fiat_sign; std::unordered_map available_currency_signs; std::vector available_lang; std::vector available_fiat; diff --git a/src/atomic.dex.provider.coinpaprika.cpp b/src/atomic.dex.provider.coinpaprika.cpp index ab7e5f07d3..dfd1f94077 100644 --- a/src/atomic.dex.provider.coinpaprika.cpp +++ b/src/atomic.dex.provider.coinpaprika.cpp @@ -81,7 +81,6 @@ namespace template void process_provider(const atomic_dex::coin_config& current_coin, Provider& rate_providers, const std::string& fiat) - { if (current_coin.coinpaprika_id != fiat) { From 112a60282748f68640cfe8108160ba4bb4afb2c6 Mon Sep 17 00:00:00 2001 From: naezith Date: Mon, 3 Aug 2020 13:32:01 +0300 Subject: [PATCH 150/515] feat(gui): add currency symbols --- atomic_qt_design/qml/Constants/General.qml | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/atomic_qt_design/qml/Constants/General.qml b/atomic_qt_design/qml/Constants/General.qml index 6b6810272b..8b462cc6d1 100644 --- a/atomic_qt_design/qml/Constants/General.qml +++ b/atomic_qt_design/qml/Constants/General.qml @@ -119,14 +119,9 @@ QtObject { } function formatFiat(received, amount, fiat) { - const symbols = { - "USD": "$", - "EUR": "€", - "BTC": Qt.platform.os === 'linux' ? "฿" : "₿", - "KMD": "KMD", - } - - return diffPrefix(received) + symbols[fiat] + " " + nFormatter(parseFloat(amount), 2) + return diffPrefix(received) + + (fiat === API.get().current_fiat ? API.get().current_fiat_sign : API.get().current_currency_sign) + + " " + nFormatter(parseFloat(amount), 2) } function formatPercent(value, show_prefix=true) { From fd537a27476f8721bfe05ab5b7c59334d183891f Mon Sep 17 00:00:00 2001 From: naezith Date: Mon, 3 Aug 2020 21:33:56 +0300 Subject: [PATCH 151/515] feat(gui): check internet availability and block the app --- atomic_qt_design/qml/NoConnection.qml | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/atomic_qt_design/qml/NoConnection.qml b/atomic_qt_design/qml/NoConnection.qml index 701a05de95..44bc920c6b 100644 --- a/atomic_qt_design/qml/NoConnection.qml +++ b/atomic_qt_design/qml/NoConnection.qml @@ -8,34 +8,9 @@ import "Components" Rectangle { id: app - visible: !connected + visible: !API.get().internet_checker.internet_reacheable color: Style.colorTheme8 - // Check Internet Connection - property bool connected: true - property bool current_connection: true - - Timer { - interval: 5000 - running: true - repeat: true - triggeredOnStart: true - onTriggered: { - var doc = new XMLHttpRequest(); - doc.onreadystatechange = function() { - if(doc.readyState === 1) { - if(!current_connection) connected = false - current_connection = false - } - if(doc.readyState === 3) current_connection = true - if(doc.readyState === 4) connected = current_connection - } - - doc.open("GET", "http://google.com") - doc.send() - } - } - ColumnLayout { anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter From 2f7bc61c57273f1b0a8419494052be12086da2e3 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Mon, 3 Aug 2020 23:06:37 +0200 Subject: [PATCH 152/515] enhancement(coding_style): use same coding style for notification --- src/atomic.dex.app.cpp | 24 ++++++------ src/atomic.dex.app.hpp | 87 ++++++++++++++++++++++-------------------- 2 files changed, 57 insertions(+), 54 deletions(-) diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index ae6d94640b..ffcecf3e4d 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -406,14 +406,14 @@ namespace atomic_dex atomic_dex::application::set_current_balance_fiat_all(QString current_fiat_all_balance) noexcept { this->m_current_balance_all = std::move(current_fiat_all_balance); - emit on_fiat_balance_all_changed(); + emit onFiatBalanceAllChanged(); } void application::set_second_current_balance_fiat_all(QString current_fiat_all_balance) noexcept { this->m_second_current_balance_all = std::move(current_fiat_all_balance); - emit on_second_fiat_balance_all_changed(); + emit onSecondFiatBalanceAllChanged(); } application::application(QObject* pParent) noexcept : @@ -527,9 +527,9 @@ namespace atomic_dex spdlog::info("change currency {} to {}", m_config.current_currency, current_currency.toStdString()); atomic_dex::change_currency(m_config, current_currency.toStdString()); this->m_portfolio->update_currency_values(); - emit on_currency_changed(); - emit on_currency_sign_changed(); - emit on_fiat_sign_changed(); + emit onCurrencyChanged(); + emit onCurrencySignChanged(); + emit onFiatSignChanged(); } } @@ -546,7 +546,7 @@ namespace atomic_dex { spdlog::info("change fiat {} to {}", m_config.current_fiat, current_fiat.toStdString()); atomic_dex::change_fiat(m_config, current_fiat.toStdString()); - emit on_fiat_changed(); + emit onFiatChanged(); } } @@ -779,7 +779,7 @@ namespace atomic_dex application::set_status(QString status) noexcept { this->m_current_status = std::move(status); - emit on_status_changed(); + emit onStatusChanged(); } void @@ -897,7 +897,7 @@ namespace atomic_dex this->m_need_a_full_refresh_of_mm2 = true; this->m_wallet_manager.just_set_wallet_name(""); - emit on_wallet_default_name_changed(); + emit onWalletDefaultNameChanged(); return fs::remove(get_atomic_dex_config_folder() / "default.wallet"); } @@ -1021,8 +1021,8 @@ namespace atomic_dex [[maybe_unused]] auto res = this->m_translator.load("atomic_qt_" + current_lang, QLatin1String(":/atomic_qt_design/assets/languages")); assert(res); this->m_app->installTranslator(&m_translator); - emit on_lang_changed(); - emit lang_changed(); + emit onLangChanged(); + emit langChanged(); } void @@ -1384,7 +1384,7 @@ namespace atomic_dex application::set_wallet_default_name(QString wallet_name) noexcept { m_wallet_manager.set_wallet_default_name(std::move(wallet_name)); - emit on_wallet_default_name_changed(); + emit onWalletDefaultNameChanged(); } bool @@ -1531,7 +1531,7 @@ namespace atomic_dex namespace atomic_dex { internet_service_checker* - application::get_internet_checker() const noexcept + application::getInternetChecker() const noexcept { return m_internet_service_checker; } diff --git a/src/atomic.dex.app.hpp b/src/atomic.dex.app.hpp index 65915fe393..d4b52146d6 100644 --- a/src/atomic.dex.app.hpp +++ b/src/atomic.dex.app.hpp @@ -53,7 +53,7 @@ namespace atomic_dex Q_OBJECT //! Properties - Q_PROPERTY(QString empty_string READ get_empty_string NOTIFY lang_changed) + Q_PROPERTY(QString empty_string READ get_empty_string NOTIFY langChanged) Q_PROPERTY(QList enabled_coins READ get_enabled_coins NOTIFY enabledCoinsChanged) Q_PROPERTY(QList enableable_coins READ get_enableable_coins NOTIFY enableableCoinsChanged) Q_PROPERTY(QObject* current_coin_info READ get_current_coin_info NOTIFY coinInfoChanged) @@ -63,23 +63,23 @@ namespace atomic_dex Q_PROPERTY(candlestick_charts_model* candlestick_charts_mdl READ get_candlestick_charts NOTIFY candlestickChartsChanged) Q_PROPERTY(QVariant update_status READ get_update_status NOTIFY updateStatusChanged) Q_PROPERTY(portfolio_model* portfolio_mdl READ get_portfolio NOTIFY portfolioChanged) - Q_PROPERTY(internet_service_checker* internet_checker READ get_internet_checker) - Q_PROPERTY(QString current_currency READ get_current_currency WRITE set_current_currency NOTIFY on_currency_changed) - Q_PROPERTY(QString current_currency_sign READ get_current_currency_sign NOTIFY on_currency_sign_changed) - Q_PROPERTY(QString current_fiat_sign READ get_current_fiat_sign NOTIFY on_fiat_sign_changed) - Q_PROPERTY(QString current_fiat READ get_current_fiat WRITE set_current_fiat NOTIFY on_fiat_changed) - Q_PROPERTY(QString lang READ get_current_lang WRITE set_current_lang NOTIFY on_lang_changed) - Q_PROPERTY(QString wallet_default_name READ get_wallet_default_name WRITE set_wallet_default_name NOTIFY on_wallet_default_name_changed) - Q_PROPERTY(QString balance_fiat_all READ get_balance_fiat_all WRITE set_current_balance_fiat_all NOTIFY on_fiat_balance_all_changed) - Q_PROPERTY(QString second_balance_fiat_all READ get_second_balance_fiat_all WRITE set_second_current_balance_fiat_all NOTIFY - on_second_fiat_balance_all_changed) - Q_PROPERTY(QString initial_loading_status READ get_status WRITE set_status NOTIFY on_status_changed) + Q_PROPERTY(internet_service_checker* internet_checker READ getInternetChecker NOTIFY internetCheckerChanged) + Q_PROPERTY(QString current_currency READ get_current_currency WRITE set_current_currency NOTIFY onCurrencyChanged) + Q_PROPERTY(QString current_currency_sign READ get_current_currency_sign NOTIFY onCurrencySignChanged) + Q_PROPERTY(QString current_fiat_sign READ get_current_fiat_sign NOTIFY onFiatSignChanged) + Q_PROPERTY(QString current_fiat READ get_current_fiat WRITE set_current_fiat NOTIFY onFiatChanged) + Q_PROPERTY(QString lang READ get_current_lang WRITE set_current_lang NOTIFY onLangChanged) + Q_PROPERTY(QString wallet_default_name READ get_wallet_default_name WRITE set_wallet_default_name NOTIFY onWalletDefaultNameChanged) + Q_PROPERTY(QString balance_fiat_all READ get_balance_fiat_all WRITE set_current_balance_fiat_all NOTIFY onFiatBalanceAllChanged) + Q_PROPERTY( + QString second_balance_fiat_all READ get_second_balance_fiat_all WRITE set_second_current_balance_fiat_all NOTIFY onSecondFiatBalanceAllChanged) + Q_PROPERTY(QString initial_loading_status READ get_status WRITE set_status NOTIFY onStatusChanged) private: //! Private function - void refresh_transactions(const mm2& mm2); - void refresh_fiat_balance(const mm2& mm2, const coinpaprika_provider& paprika); - void refresh_address(mm2& mm2); + void refresh_transactions(const atomic_dex::mm2& mm2_system); + void refresh_fiat_balance(const atomic_dex::mm2& mm2_system, const coinpaprika_provider& coinpaprika_system); + void refresh_address(atomic_dex::mm2& mm2_system); void connect_signals(); void tick(); @@ -120,23 +120,25 @@ namespace atomic_dex void on_start_fetching_new_ohlc_data_event(const start_fetching_new_ohlc_data&); //! Properties Getter - static const QString& get_empty_string(); - mm2& get_mm2() noexcept; - const mm2& get_mm2() const noexcept; - coinpaprika_provider& get_paprika() noexcept; - entt::dispatcher& get_dispatcher() noexcept; - QObject* get_current_coin_info() const noexcept; - addressbook_model* get_addressbook() const noexcept; - portfolio_model* get_portfolio() const noexcept; - orders_model* get_orders() const noexcept; - candlestick_charts_model* get_candlestick_charts() const noexcept; - internet_service_checker* get_internet_checker() const noexcept;; - qt_orderbook_wrapper* get_orderbook_wrapper() const noexcept; - QVariantList get_enabled_coins() const noexcept; - QVariantList get_enableable_coins() const noexcept; - QString get_current_currency() const noexcept; - QString get_current_currency_sign() const noexcept; - QString get_current_fiat_sign() const noexcept;; + static const QString& get_empty_string(); + mm2& get_mm2() noexcept; + const mm2& get_mm2() const noexcept; + coinpaprika_provider& get_paprika() noexcept; + entt::dispatcher& get_dispatcher() noexcept; + QObject* get_current_coin_info() const noexcept; + addressbook_model* get_addressbook() const noexcept; + portfolio_model* get_portfolio() const noexcept; + orders_model* get_orders() const noexcept; + candlestick_charts_model* get_candlestick_charts() const noexcept; + internet_service_checker* getInternetChecker() const noexcept; + ; + qt_orderbook_wrapper* get_orderbook_wrapper() const noexcept; + QVariantList get_enabled_coins() const noexcept; + QVariantList get_enableable_coins() const noexcept; + QString get_current_currency() const noexcept; + QString get_current_currency_sign() const noexcept; + QString get_current_fiat_sign() const noexcept; + ; QString get_current_fiat() const noexcept; QString get_current_lang() const noexcept; QString get_balance_fiat_all() const noexcept; @@ -236,17 +238,17 @@ namespace atomic_dex void enabledCoinsChanged(); void enableableCoinsChanged(); void coinInfoChanged(); - void on_currency_changed(); - void on_currency_sign_changed(); - void on_fiat_sign_changed(); - void on_fiat_changed(); + void onCurrencyChanged(); + void onCurrencySignChanged(); + void onFiatSignChanged(); + void onFiatChanged(); void on_second_fiat_changed(); - void on_lang_changed(); - void lang_changed(); - void on_fiat_balance_all_changed(); - void on_second_fiat_balance_all_changed(); - void on_status_changed(); - void on_wallet_default_name_changed(); + void onLangChanged(); + void langChanged(); + void onFiatBalanceAllChanged(); + void onSecondFiatBalanceAllChanged(); + void onStatusChanged(); + void onWalletDefaultNameChanged(); void myOrdersUpdated(); void addressbookChanged(); void OHLCDataUpdated(); @@ -255,6 +257,7 @@ namespace atomic_dex void ordersChanged(); void candlestickChartsChanged(); void orderbookChanged(); + void internetCheckerChanged(); public slots: void exit_handler(); From a559d776fcdd328a3bdbe50fe70a51dea728163e Mon Sep 17 00:00:00 2001 From: romanszterg Date: Mon, 3 Aug 2020 23:33:10 +0200 Subject: [PATCH 153/515] enhancement(code): refactor app.hpp to reduce bloating code --- src/atomic.dex.app.cpp | 39 ++++++----- src/atomic.dex.app.hpp | 145 ++++++++++++++++++++--------------------- 2 files changed, 94 insertions(+), 90 deletions(-) diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index ffcecf3e4d..f4f99d5e09 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -136,8 +136,7 @@ namespace atomic_dex application::disable_coins(const QStringList& coins) { std::vector coins_std; - - this->m_portfolio->disable_coins(coins); + qobject_cast(m_manager_models.at("portfolio"))->disable_coins(coins); coins_std.reserve(coins.size()); for (auto&& coin: coins) { coins_std.push_back(coin.toStdString()); } get_mm2().disable_multiple_coins(coins_std); @@ -275,7 +274,7 @@ namespace atomic_dex case action::refresh_portfolio_ticker_balance: if (mm2.is_mm2_running()) { - this->m_portfolio->update_balance_values(*this->m_ticker_balance_to_refresh); + qobject_cast(m_manager_models.at("portfolio"))->update_balance_values(*m_ticker_balance_to_refresh); } break; case action::post_process_orders_finished: @@ -420,9 +419,12 @@ namespace atomic_dex QObject(pParent), m_update_status(QJsonObject{ {"update_needed", false}, {"changelog", ""}, {"current_version", ""}, {"download_url", ""}, {"new_version", ""}, {"rpc_code", 0}, {"status", ""}}), - m_coin_info(new current_coin_info(dispatcher_, this)), m_addressbook(new addressbook_model(this->m_wallet_manager, this)), - m_portfolio(new portfolio_model(this->system_manager_, this->m_config, this)), m_orders(new orders_model(this->system_manager_, this)), - m_candlestick_chart_ohlc(new candlestick_charts_model(this->system_manager_, this)), m_orderbook(new qt_orderbook_wrapper(this->system_manager_, this)), + m_coin_info(new current_coin_info(dispatcher_, this)), + m_manager_models{ + {"addressbook", new addressbook_model(this->m_wallet_manager, this)}, + {"portfolio", new portfolio_model(this->system_manager_, this->m_config, this)}}, + m_orders(new orders_model(this->system_manager_, this)), m_candlestick_chart_ohlc(new candlestick_charts_model(this->system_manager_, this)), + m_orderbook(new qt_orderbook_wrapper(this->system_manager_, this)), m_internet_service_checker(std::addressof(system_manager_.create_system(this))) { get_dispatcher().sink().connect<&application::on_refresh_update_status_event>(*this); @@ -498,7 +500,7 @@ namespace atomic_dex { //! This event is called when a call is enabled and cex provider finished fetch datas spdlog::debug("{} l{}", __FUNCTION__, __LINE__); - this->m_portfolio->initialize_portfolio(evt.ticker); + qobject_cast(m_manager_models.at("portfolio"))->initialize_portfolio(evt.ticker); } QString @@ -526,7 +528,7 @@ namespace atomic_dex { spdlog::info("change currency {} to {}", m_config.current_currency, current_currency.toStdString()); atomic_dex::change_currency(m_config, current_currency.toStdString()); - this->m_portfolio->update_currency_values(); + qobject_cast(m_manager_models.at("portfolio"))->update_currency_values(); emit onCurrencyChanged(); emit onCurrencySignChanged(); emit onFiatSignChanged(); @@ -855,14 +857,16 @@ namespace atomic_dex } //! Clear models - if (auto count = this->m_addressbook->rowCount(); count > 0) + addressbook_model* addressbook = qobject_cast(m_manager_models.at("addressbook")); + if (auto count = addressbook->rowCount(); count > 0) { - this->m_addressbook->removeRows(0, count); + addressbook->removeRows(0, count); } - if (auto count = this->m_portfolio->rowCount(QModelIndex()); count > 0) + portfolio_model* portfolio = qobject_cast(m_manager_models.at("portfolio")); + if (auto count = portfolio->rowCount(QModelIndex()); count > 0) { - this->m_portfolio->removeRows(0, count, QModelIndex()); + portfolio->removeRows(0, count, QModelIndex()); } if (auto count = this->m_orders->rowCount(QModelIndex()); count > 0) @@ -1189,9 +1193,9 @@ namespace atomic_dex { application::~application() noexcept { - if (this->m_addressbook->rowCount() > 0) + if (auto addressbook = qobject_cast(m_manager_models.at("addressbook")); addressbook->rowCount() > 0) { - this->m_addressbook->removeRows(0, this->m_addressbook->rowCount()); + addressbook->removeRows(0, addressbook->rowCount()); } export_swaps_json(); } @@ -1327,7 +1331,7 @@ namespace atomic_dex addressbook_model* application::get_addressbook() const noexcept { - return m_addressbook; + return qobject_cast(m_manager_models.at("addressbook")); } } // namespace atomic_dex @@ -1367,7 +1371,7 @@ namespace atomic_dex portfolio_model* application::get_portfolio() const noexcept { - return m_portfolio; + return qobject_cast(m_manager_models.at("portfolio")); } } // namespace atomic_dex @@ -1402,7 +1406,8 @@ namespace atomic_dex }); if (res) { - this->m_addressbook->initializeFromCfg(); + addressbook_model* addressbook = qobject_cast(m_manager_models.at("addressbook")); + addressbook->initializeFromCfg(); } return res; } diff --git a/src/atomic.dex.app.hpp b/src/atomic.dex.app.hpp index d4b52146d6..362d8bad3d 100644 --- a/src/atomic.dex.app.hpp +++ b/src/atomic.dex.app.hpp @@ -75,15 +75,16 @@ namespace atomic_dex QString second_balance_fiat_all READ get_second_balance_fiat_all WRITE set_second_current_balance_fiat_all NOTIFY onSecondFiatBalanceAllChanged) Q_PROPERTY(QString initial_loading_status READ get_status WRITE set_status NOTIFY onStatusChanged) - private: //! Private function void refresh_transactions(const atomic_dex::mm2& mm2_system); void refresh_fiat_balance(const atomic_dex::mm2& mm2_system, const coinpaprika_provider& coinpaprika_system); void refresh_address(atomic_dex::mm2& mm2_system); void connect_signals(); void tick(); + void process_refresh_enabled_coin_action(); + void process_refresh_current_ticker_infos(); - public: + //! Private enums enum class action { refresh_enabled_coin = 0, @@ -97,6 +98,58 @@ namespace atomic_dex post_process_orderbook_finished = 8 }; + //! Private typedefs + using t_actions_queue = boost::lockfree::queue; + using t_synchronized_string = boost::synchronized_value; + using t_manager_model_registry = std::unordered_map; + + //! Private members fields + + //! CFG + atomic_dex::cfg m_config{load_cfg()}; + + //! QT Application + std::shared_ptr m_app; + + //! Wallet Manager + atomic_dex::qt_wallet_manager m_wallet_manager; + + //! Threading + t_actions_queue m_actions_queue{g_max_actions_size}; + t_synchronized_string m_ticker_balance_to_refresh; + + //! Properties field + bool m_need_a_full_refresh_of_mm2{false}; + QVariantList m_enabled_coins; + QVariantList m_enableable_coins; + QVariant m_update_status; + QTranslator m_translator; + QString m_current_lang{QString::fromStdString(m_config.current_lang)}; + QString m_current_status{"None"}; + QString m_current_balance_all{"0.00"}; + QString m_second_current_balance_all{"0.00"}; + current_coin_info* m_coin_info; + + //! MGR + t_manager_model_registry m_manager_models; + + //! Orders model based on the current wallet + orders_model* m_orders; + + //! Candlestick charts + candlestick_charts_model* m_candlestick_chart_ohlc; + std::atomic_bool m_candlestick_need_a_reset{false}; + + //! Orderbook Model Wrapper + qt_orderbook_wrapper* m_orderbook; + std::atomic_bool m_orderbook_need_a_reset{false}; + + //! Internet service checker + internet_service_checker* m_internet_service_checker; + + //! Miscs Threading settings + std::atomic_bool m_about_to_exit_app{false}; + public: //! Constructor explicit application(QObject* pParent = nullptr) noexcept; @@ -120,25 +173,23 @@ namespace atomic_dex void on_start_fetching_new_ohlc_data_event(const start_fetching_new_ohlc_data&); //! Properties Getter - static const QString& get_empty_string(); - mm2& get_mm2() noexcept; - const mm2& get_mm2() const noexcept; - coinpaprika_provider& get_paprika() noexcept; - entt::dispatcher& get_dispatcher() noexcept; - QObject* get_current_coin_info() const noexcept; - addressbook_model* get_addressbook() const noexcept; - portfolio_model* get_portfolio() const noexcept; - orders_model* get_orders() const noexcept; - candlestick_charts_model* get_candlestick_charts() const noexcept; - internet_service_checker* getInternetChecker() const noexcept; - ; - qt_orderbook_wrapper* get_orderbook_wrapper() const noexcept; - QVariantList get_enabled_coins() const noexcept; - QVariantList get_enableable_coins() const noexcept; - QString get_current_currency() const noexcept; - QString get_current_currency_sign() const noexcept; - QString get_current_fiat_sign() const noexcept; - ; + static const QString& get_empty_string(); + mm2& get_mm2() noexcept; + const mm2& get_mm2() const noexcept; + coinpaprika_provider& get_paprika() noexcept; + entt::dispatcher& get_dispatcher() noexcept; + QObject* get_current_coin_info() const noexcept; + addressbook_model* get_addressbook() const noexcept; + portfolio_model* get_portfolio() const noexcept; + orders_model* get_orders() const noexcept; + candlestick_charts_model* get_candlestick_charts() const noexcept; + internet_service_checker* getInternetChecker() const noexcept; + qt_orderbook_wrapper* get_orderbook_wrapper() const noexcept; + QVariantList get_enabled_coins() const noexcept; + QVariantList get_enableable_coins() const noexcept; + QString get_current_currency() const noexcept; + QString get_current_currency_sign() const noexcept; + QString get_current_fiat_sign() const noexcept; QString get_current_fiat() const noexcept; QString get_current_lang() const noexcept; QString get_balance_fiat_all() const noexcept; @@ -260,57 +311,5 @@ namespace atomic_dex void internetCheckerChanged(); public slots: void exit_handler(); - - private: - void process_refresh_enabled_coin_action(); - void process_refresh_current_ticker_infos(); - - private: - //! CFG - atomic_dex::cfg m_config{load_cfg()}; - - //! QT Application - std::shared_ptr m_app; - - //! Wallet Manager - atomic_dex::qt_wallet_manager m_wallet_manager; - - //! Private members - boost::lockfree::queue m_actions_queue{g_max_actions_size}; - boost::synchronized_value m_ticker_balance_to_refresh; - - bool m_need_a_full_refresh_of_mm2{false}; - QVariantList m_enabled_coins; - QVariantList m_enableable_coins; - QVariant m_update_status; - QTranslator m_translator; - QString m_current_lang{QString::fromStdString(m_config.current_lang)}; - QString m_current_status{"None"}; - QString m_current_balance_all{"0.00"}; - QString m_second_current_balance_all{"0.00"}; - current_coin_info* m_coin_info; - - - //! Addressbook based on the current wallet - addressbook_model* m_addressbook; - - //! Portfolio based on the current wallet - portfolio_model* m_portfolio; - - //! Orders model based on the current wallet - orders_model* m_orders; - - //! Candlestick charts - candlestick_charts_model* m_candlestick_chart_ohlc; - std::atomic_bool m_candlestick_need_a_reset{false}; - - //! Orderbook Model Wrapper - qt_orderbook_wrapper* m_orderbook; - std::atomic_bool m_orderbook_need_a_reset{false}; - - //! Internet service checker - internet_service_checker* m_internet_service_checker; - - std::atomic_bool m_about_to_exit_app{false}; }; } // namespace atomic_dex From 51f85ea225d9d7e01ddb9a68895e3d5fc94ca19f Mon Sep 17 00:00:00 2001 From: romanszterg Date: Mon, 3 Aug 2020 23:44:30 +0200 Subject: [PATCH 154/515] enhancement(code): continue refactor --- src/atomic.dex.app.cpp | 15 --------- src/atomic.dex.app.hpp | 73 +++++++++++++----------------------------- 2 files changed, 23 insertions(+), 65 deletions(-) diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index f4f99d5e09..9e4c0a4e0c 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -36,8 +36,6 @@ # include #endif -/*#define ENABLE_ENCODER_GENERIC -#include "QZXing.h"*/ //! Project Headers #include "atomic.dex.app.hpp" #include "atomic.dex.mm2.hpp" @@ -395,12 +393,6 @@ namespace atomic_dex return m_current_balance_all; } - QString - application::get_second_balance_fiat_all() const noexcept - { - return m_second_current_balance_all; - } - void atomic_dex::application::set_current_balance_fiat_all(QString current_fiat_all_balance) noexcept { @@ -408,13 +400,6 @@ namespace atomic_dex emit onFiatBalanceAllChanged(); } - void - application::set_second_current_balance_fiat_all(QString current_fiat_all_balance) noexcept - { - this->m_second_current_balance_all = std::move(current_fiat_all_balance); - emit onSecondFiatBalanceAllChanged(); - } - application::application(QObject* pParent) noexcept : QObject(pParent), m_update_status(QJsonObject{ diff --git a/src/atomic.dex.app.hpp b/src/atomic.dex.app.hpp index 362d8bad3d..9d04696b0d 100644 --- a/src/atomic.dex.app.hpp +++ b/src/atomic.dex.app.hpp @@ -71,8 +71,6 @@ namespace atomic_dex Q_PROPERTY(QString lang READ get_current_lang WRITE set_current_lang NOTIFY onLangChanged) Q_PROPERTY(QString wallet_default_name READ get_wallet_default_name WRITE set_wallet_default_name NOTIFY onWalletDefaultNameChanged) Q_PROPERTY(QString balance_fiat_all READ get_balance_fiat_all WRITE set_current_balance_fiat_all NOTIFY onFiatBalanceAllChanged) - Q_PROPERTY( - QString second_balance_fiat_all READ get_second_balance_fiat_all WRITE set_second_current_balance_fiat_all NOTIFY onSecondFiatBalanceAllChanged) Q_PROPERTY(QString initial_loading_status READ get_status WRITE set_status NOTIFY onStatusChanged) //! Private function @@ -99,56 +97,34 @@ namespace atomic_dex }; //! Private typedefs - using t_actions_queue = boost::lockfree::queue; - using t_synchronized_string = boost::synchronized_value; + using t_actions_queue = boost::lockfree::queue; + using t_synchronized_string = boost::synchronized_value; using t_manager_model_registry = std::unordered_map; //! Private members fields - - //! CFG - atomic_dex::cfg m_config{load_cfg()}; - - //! QT Application + atomic_dex::cfg m_config{load_cfg()}; std::shared_ptr m_app; - - //! Wallet Manager atomic_dex::qt_wallet_manager m_wallet_manager; - - //! Threading - t_actions_queue m_actions_queue{g_max_actions_size}; - t_synchronized_string m_ticker_balance_to_refresh; - - //! Properties field - bool m_need_a_full_refresh_of_mm2{false}; - QVariantList m_enabled_coins; - QVariantList m_enableable_coins; - QVariant m_update_status; - QTranslator m_translator; - QString m_current_lang{QString::fromStdString(m_config.current_lang)}; - QString m_current_status{"None"}; - QString m_current_balance_all{"0.00"}; - QString m_second_current_balance_all{"0.00"}; - current_coin_info* m_coin_info; - - //! MGR - t_manager_model_registry m_manager_models; - - //! Orders model based on the current wallet - orders_model* m_orders; - - //! Candlestick charts - candlestick_charts_model* m_candlestick_chart_ohlc; - std::atomic_bool m_candlestick_need_a_reset{false}; - - //! Orderbook Model Wrapper - qt_orderbook_wrapper* m_orderbook; - std::atomic_bool m_orderbook_need_a_reset{false}; - - //! Internet service checker - internet_service_checker* m_internet_service_checker; - - //! Miscs Threading settings - std::atomic_bool m_about_to_exit_app{false}; + t_actions_queue m_actions_queue{g_max_actions_size}; + t_synchronized_string m_ticker_balance_to_refresh; + bool m_need_a_full_refresh_of_mm2{false}; + QVariantList m_enabled_coins; + QVariantList m_enableable_coins; + QVariant m_update_status; + QTranslator m_translator; + QString m_current_lang{QString::fromStdString(m_config.current_lang)}; + QString m_current_status{"None"}; + QString m_current_balance_all{"0.00"}; + QString m_second_current_balance_all{"0.00"}; + current_coin_info* m_coin_info; + t_manager_model_registry m_manager_models; + orders_model* m_orders; + candlestick_charts_model* m_candlestick_chart_ohlc; + std::atomic_bool m_candlestick_need_a_reset{false}; + qt_orderbook_wrapper* m_orderbook; + std::atomic_bool m_orderbook_need_a_reset{false}; + internet_service_checker* m_internet_service_checker; + std::atomic_bool m_about_to_exit_app{false}; public: //! Constructor @@ -193,7 +169,6 @@ namespace atomic_dex QString get_current_fiat() const noexcept; QString get_current_lang() const noexcept; QString get_balance_fiat_all() const noexcept; - QString get_second_balance_fiat_all() const noexcept; QString get_wallet_default_name() const noexcept; QString get_status() const noexcept; QVariant get_update_status() const noexcept; @@ -205,7 +180,6 @@ namespace atomic_dex void set_current_lang(const QString& current_lang) noexcept; void set_wallet_default_name(QString wallet_default_name) noexcept; void set_current_balance_fiat_all(QString current_fiat_all_balance) noexcept; - void set_second_current_balance_fiat_all(QString current_fiat_all_balance) noexcept; void set_status(QString status) noexcept; void set_qt_app(std::shared_ptr app) noexcept; @@ -293,7 +267,6 @@ namespace atomic_dex void onCurrencySignChanged(); void onFiatSignChanged(); void onFiatChanged(); - void on_second_fiat_changed(); void onLangChanged(); void langChanged(); void onFiatBalanceAllChanged(); From 3cba4911fbb3b159b5616b8c89862e7a5c970546 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Tue, 4 Aug 2020 07:58:02 +0200 Subject: [PATCH 155/515] enhancement(code): change bids logic for orderbook --- src/atomic.dex.app.cpp | 18 ++++++++++-------- src/atomic.dex.app.hpp | 3 ++- src/atomic.dex.mm2.api.cpp | 8 +++++++- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index 9e4c0a4e0c..e0362a906d 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -278,13 +278,13 @@ namespace atomic_dex case action::post_process_orders_finished: if (mm2.is_mm2_running()) { - this->m_orders->refresh_or_insert_orders(); + qobject_cast(m_manager_models.at("orders"))->refresh_or_insert_orders(); } break; case action::post_process_swaps_finished: if (mm2.is_mm2_running()) { - this->m_orders->refresh_or_insert_swaps(); + qobject_cast(m_manager_models.at("orders"))->refresh_or_insert_swaps(); } break; case action::post_process_orderbook_finished: @@ -407,8 +407,9 @@ namespace atomic_dex m_coin_info(new current_coin_info(dispatcher_, this)), m_manager_models{ {"addressbook", new addressbook_model(this->m_wallet_manager, this)}, - {"portfolio", new portfolio_model(this->system_manager_, this->m_config, this)}}, - m_orders(new orders_model(this->system_manager_, this)), m_candlestick_chart_ohlc(new candlestick_charts_model(this->system_manager_, this)), + {"portfolio", new portfolio_model(this->system_manager_, this->m_config, this)}, + {"orders", new orders_model(this->system_manager_, this)}}, + m_candlestick_chart_ohlc(new candlestick_charts_model(this->system_manager_, this)), m_orderbook(new qt_orderbook_wrapper(this->system_manager_, this)), m_internet_service_checker(std::addressof(system_manager_.create_system(this))) { @@ -854,11 +855,12 @@ namespace atomic_dex portfolio->removeRows(0, count, QModelIndex()); } - if (auto count = this->m_orders->rowCount(QModelIndex()); count > 0) + orders_model* orders = qobject_cast(m_manager_models.at("orders")); + if (auto count = orders->rowCount(QModelIndex()); count > 0) { - this->m_orders->removeRows(0, count, QModelIndex()); + orders->removeRows(0, count, QModelIndex()); } - this->m_orders->clear_registry(); + orders->clear_registry(); this->m_candlestick_chart_ohlc->clear_data(); this->m_orderbook->clear_orderbook(); @@ -1346,7 +1348,7 @@ namespace atomic_dex orders_model* application::get_orders() const noexcept { - return m_orders; + return qobject_cast(m_manager_models.at("orders")); } } // namespace atomic_dex diff --git a/src/atomic.dex.app.hpp b/src/atomic.dex.app.hpp index 9d04696b0d..794f12f635 100644 --- a/src/atomic.dex.app.hpp +++ b/src/atomic.dex.app.hpp @@ -16,6 +16,7 @@ #pragma once +//! QT Headers #include #include #include @@ -118,7 +119,7 @@ namespace atomic_dex QString m_second_current_balance_all{"0.00"}; current_coin_info* m_coin_info; t_manager_model_registry m_manager_models; - orders_model* m_orders; + //orders_model* m_orders; candlestick_charts_model* m_candlestick_chart_ohlc; std::atomic_bool m_candlestick_need_a_reset{false}; qt_orderbook_wrapper* m_orderbook; diff --git a/src/atomic.dex.mm2.api.cpp b/src/atomic.dex.mm2.api.cpp index 5d92b7aa82..2b490a3103 100644 --- a/src/atomic.dex.mm2.api.cpp +++ b/src/atomic.dex.mm2.api.cpp @@ -442,7 +442,13 @@ namespace mm2::api answer.asks_total_volume = result_asks_f.str(); t_float_50 result_bids_f("0"); - for (auto&& cur_bids: answer.bids) { result_bids_f = result_bids_f + t_float_50(cur_bids.maxvolume); } + for (auto& cur_bids: answer.bids) + { + cur_bids.total = cur_bids.maxvolume; + t_float_50 new_volume = t_float_50(cur_bids.maxvolume) / t_float_50(cur_bids.price); + cur_bids.maxvolume = adjust_precision(new_volume.str()); + result_bids_f = result_bids_f + t_float_50(cur_bids.maxvolume); + } answer.bids_total_volume = result_bids_f.str(); for (auto&& cur_asks: answer.asks) From 42d61f4bceca3694e26a5bbc22aef51abf033033 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Tue, 4 Aug 2020 08:28:55 +0200 Subject: [PATCH 156/515] enhancement(code): coding style --- src/atomic.dex.app.cpp | 2 +- src/atomic.dex.app.hpp | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index e0362a906d..fcfa2c6e8c 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -1523,7 +1523,7 @@ namespace atomic_dex namespace atomic_dex { internet_service_checker* - application::getInternetChecker() const noexcept + application::get_internet_checker() const noexcept { return m_internet_service_checker; } diff --git a/src/atomic.dex.app.hpp b/src/atomic.dex.app.hpp index 794f12f635..9093b3ced1 100644 --- a/src/atomic.dex.app.hpp +++ b/src/atomic.dex.app.hpp @@ -64,7 +64,7 @@ namespace atomic_dex Q_PROPERTY(candlestick_charts_model* candlestick_charts_mdl READ get_candlestick_charts NOTIFY candlestickChartsChanged) Q_PROPERTY(QVariant update_status READ get_update_status NOTIFY updateStatusChanged) Q_PROPERTY(portfolio_model* portfolio_mdl READ get_portfolio NOTIFY portfolioChanged) - Q_PROPERTY(internet_service_checker* internet_checker READ getInternetChecker NOTIFY internetCheckerChanged) + Q_PROPERTY(internet_service_checker* internet_checker READ get_internet_checker NOTIFY internetCheckerChanged) Q_PROPERTY(QString current_currency READ get_current_currency WRITE set_current_currency NOTIFY onCurrencyChanged) Q_PROPERTY(QString current_currency_sign READ get_current_currency_sign NOTIFY onCurrencySignChanged) Q_PROPERTY(QString current_fiat_sign READ get_current_fiat_sign NOTIFY onFiatSignChanged) @@ -116,10 +116,8 @@ namespace atomic_dex QString m_current_lang{QString::fromStdString(m_config.current_lang)}; QString m_current_status{"None"}; QString m_current_balance_all{"0.00"}; - QString m_second_current_balance_all{"0.00"}; current_coin_info* m_coin_info; t_manager_model_registry m_manager_models; - //orders_model* m_orders; candlestick_charts_model* m_candlestick_chart_ohlc; std::atomic_bool m_candlestick_need_a_reset{false}; qt_orderbook_wrapper* m_orderbook; @@ -160,7 +158,7 @@ namespace atomic_dex portfolio_model* get_portfolio() const noexcept; orders_model* get_orders() const noexcept; candlestick_charts_model* get_candlestick_charts() const noexcept; - internet_service_checker* getInternetChecker() const noexcept; + internet_service_checker* get_internet_checker() const noexcept; qt_orderbook_wrapper* get_orderbook_wrapper() const noexcept; QVariantList get_enabled_coins() const noexcept; QVariantList get_enableable_coins() const noexcept; From a7c2c8d8a204cc4f31eaaf4d6c0dd5863f8c9dc9 Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 4 Aug 2020 13:35:52 +0300 Subject: [PATCH 157/515] feat(gui): fix scientific notation happening before satoshi --- atomic_qt_design/qml/Constants/General.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomic_qt_design/qml/Constants/General.qml b/atomic_qt_design/qml/Constants/General.qml index 8b462cc6d1..7b5d0e32b2 100644 --- a/atomic_qt_design/qml/Constants/General.qml +++ b/atomic_qt_design/qml/Constants/General.qml @@ -98,7 +98,7 @@ QtObject { } function nFormatter(num, digits) { - if(num < 1E5) return num + if(num < 1E5) return General.formatDouble(num) const si = [ { value: 1, symbol: "" }, From ab7b5716352bff8d6275b31751099b09a9e6f03d Mon Sep 17 00:00:00 2001 From: romanszterg Date: Tue, 4 Aug 2020 13:28:50 +0200 Subject: [PATCH 158/515] feat(internet_service): add a retry invokable function --- src/atomic.dex.qt.internet.checker.service.cpp | 11 +++++++---- src/atomic.dex.qt.internet.checker.service.hpp | 2 ++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/atomic.dex.qt.internet.checker.service.cpp b/src/atomic.dex.qt.internet.checker.service.cpp index ff843b5625..6a6a0c46fc 100644 --- a/src/atomic.dex.qt.internet.checker.service.cpp +++ b/src/atomic.dex.qt.internet.checker.service.cpp @@ -41,7 +41,10 @@ namespace atomic_dex namespace atomic_dex { - internet_service_checker::internet_service_checker(entt::registry& registry, QObject* parent) : QObject(parent), system(registry) + internet_service_checker::internet_service_checker(entt::registry& registry, QObject* parent) : QObject(parent), system(registry) { retry(); } + + void + atomic_dex::internet_service_checker::retry() noexcept { m_update_clock = std::chrono::high_resolution_clock::now(); this->fetch_internet_connection(); @@ -66,10 +69,10 @@ namespace atomic_dex { spdlog::info("fetching internet status begin"); spawn([this]() { - is_google_reacheable = am_i_able_to_reach_this_endpoint("https://www.google.com"); - is_paprika_provider_alive = am_i_able_to_reach_this_endpoint("https://api.coinpaprika.com/v1/coins/btc-bitcoin"); + is_google_reacheable = am_i_able_to_reach_this_endpoint("https://www.google.com"); + is_paprika_provider_alive = am_i_able_to_reach_this_endpoint("https://api.coinpaprika.com/v1/coins/btc-bitcoin"); is_our_private_endpoint_reacheable = am_i_able_to_reach_this_endpoint("https://komodo.live:3333/api/v1/ohlc/tickers_list"); - bool res = is_google_reacheable || is_paprika_provider_alive || is_our_private_endpoint_reacheable; + bool res = is_google_reacheable || is_paprika_provider_alive || is_our_private_endpoint_reacheable; this->set_internet_alive(res); spdlog::info("fetching internet status finished, internet status is: {}", res); }); diff --git a/src/atomic.dex.qt.internet.checker.service.hpp b/src/atomic.dex.qt.internet.checker.service.hpp index d3daa9d60f..2fed70d961 100644 --- a/src/atomic.dex.qt.internet.checker.service.hpp +++ b/src/atomic.dex.qt.internet.checker.service.hpp @@ -59,6 +59,8 @@ namespace atomic_dex [[nodiscard]] bool is_internet_alive() const noexcept; void set_internet_alive(bool internet_status) noexcept; + + Q_INVOKABLE void retry() noexcept; }; } // namespace atomic_dex From a7e92520f359acae0d68d4527ab14d65d1b6ecf2 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Tue, 4 Aug 2020 13:44:31 +0200 Subject: [PATCH 159/515] feat(timer): add internet timer checker --- ...atomic.dex.qt.internet.checker.service.cpp | 20 ++++++++++++++++++- ...atomic.dex.qt.internet.checker.service.hpp | 6 ++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/atomic.dex.qt.internet.checker.service.cpp b/src/atomic.dex.qt.internet.checker.service.cpp index 6a6a0c46fc..af8f79002f 100644 --- a/src/atomic.dex.qt.internet.checker.service.cpp +++ b/src/atomic.dex.qt.internet.checker.service.cpp @@ -43,10 +43,25 @@ namespace atomic_dex { internet_service_checker::internet_service_checker(entt::registry& registry, QObject* parent) : QObject(parent), system(registry) { retry(); } + double + atomic_dex::internet_service_checker::get_seconds_left_to_auto_retry() const noexcept + { + return m_timer; + } + + void + atomic_dex::internet_service_checker::set_seconds_left_to_auto_retry(double time_left) noexcept + { + m_timer = time_left; + emit secondsLeftToAutoRetryChanged(); + } + void atomic_dex::internet_service_checker::retry() noexcept { + using namespace std::chrono_literals; m_update_clock = std::chrono::high_resolution_clock::now(); + set_seconds_left_to_auto_retry(15.0); this->fetch_internet_connection(); } @@ -57,10 +72,13 @@ namespace atomic_dex const auto now = std::chrono::high_resolution_clock::now(); const auto s = std::chrono::duration_cast(now - m_update_clock); - if (s >= 30s) + set_seconds_left_to_auto_retry(15.0 - s.count()); + spdlog::trace("timer: {}s", m_timer); + if (s >= 15s) { this->fetch_internet_connection(); m_update_clock = std::chrono::high_resolution_clock::now(); + set_seconds_left_to_auto_retry(15.0); } } diff --git a/src/atomic.dex.qt.internet.checker.service.hpp b/src/atomic.dex.qt.internet.checker.service.hpp index 2fed70d961..f267df30c6 100644 --- a/src/atomic.dex.qt.internet.checker.service.hpp +++ b/src/atomic.dex.qt.internet.checker.service.hpp @@ -30,11 +30,14 @@ namespace atomic_dex Q_OBJECT Q_PROPERTY(bool internet_reacheable READ is_internet_alive WRITE set_internet_alive NOTIFY internetStatusChanged) + Q_PROPERTY( + double seconds_left_to_auto_retry READ get_seconds_left_to_auto_retry WRITE set_seconds_left_to_auto_retry NOTIFY secondsLeftToAutoRetryChanged) //! Private typedefs using t_update_time_point = std::chrono::high_resolution_clock::time_point; //! Private members t_update_time_point m_update_clock; + double m_timer; std::atomic_bool is_internet_reacheable{true}; std::atomic_bool is_paprika_provider_alive{true}; std::atomic_bool is_cipig_electrum_alive{true}; @@ -46,6 +49,7 @@ namespace atomic_dex signals: void internetStatusChanged(); + void secondsLeftToAutoRetryChanged(); public: //! Constructor @@ -57,6 +61,8 @@ namespace atomic_dex //! QT Properties [[nodiscard]] bool is_internet_alive() const noexcept; + [[nodiscard]] double get_seconds_left_to_auto_retry() const noexcept; + void set_seconds_left_to_auto_retry(double time_left) noexcept; void set_internet_alive(bool internet_status) noexcept; From 31e5ccdd36ec4421df3f7ffaff67748a08f0d666 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Tue, 4 Aug 2020 13:49:17 +0200 Subject: [PATCH 160/515] feat(timer): remove extra logs --- src/atomic.dex.qt.internet.checker.service.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/atomic.dex.qt.internet.checker.service.cpp b/src/atomic.dex.qt.internet.checker.service.cpp index af8f79002f..29a1fb9bca 100644 --- a/src/atomic.dex.qt.internet.checker.service.cpp +++ b/src/atomic.dex.qt.internet.checker.service.cpp @@ -73,7 +73,6 @@ namespace atomic_dex const auto now = std::chrono::high_resolution_clock::now(); const auto s = std::chrono::duration_cast(now - m_update_clock); set_seconds_left_to_auto_retry(15.0 - s.count()); - spdlog::trace("timer: {}s", m_timer); if (s >= 15s) { this->fetch_internet_connection(); From a4f0d599459a4ba87a4bda69e035913379e2301c Mon Sep 17 00:00:00 2001 From: romanszterg Date: Tue, 4 Aug 2020 13:51:41 +0200 Subject: [PATCH 161/515] feat(timer): clean code --- src/atomic.dex.qt.internet.checker.service.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/atomic.dex.qt.internet.checker.service.cpp b/src/atomic.dex.qt.internet.checker.service.cpp index 29a1fb9bca..c4aa1abb95 100644 --- a/src/atomic.dex.qt.internet.checker.service.cpp +++ b/src/atomic.dex.qt.internet.checker.service.cpp @@ -37,11 +37,6 @@ namespace atomic_dex { return is_internet_reacheable.load(); } -} // namespace atomic_dex - -namespace atomic_dex -{ - internet_service_checker::internet_service_checker(entt::registry& registry, QObject* parent) : QObject(parent), system(registry) { retry(); } double atomic_dex::internet_service_checker::get_seconds_left_to_auto_retry() const noexcept @@ -55,6 +50,15 @@ namespace atomic_dex m_timer = time_left; emit secondsLeftToAutoRetryChanged(); } +} // namespace atomic_dex + +namespace atomic_dex +{ + internet_service_checker::internet_service_checker(entt::registry& registry, QObject* parent) : QObject(parent), system(registry) + { + //! Init + retry(); + } void atomic_dex::internet_service_checker::retry() noexcept From 58bb9c8e95f1f98502f9f54dff15847905dbab5e Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 4 Aug 2020 15:06:32 +0300 Subject: [PATCH 162/515] feat(gui): add connection seconds left and retry button --- atomic_qt_design/qml/NoConnection.qml | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/NoConnection.qml b/atomic_qt_design/qml/NoConnection.qml index 44bc920c6b..d418e1b800 100644 --- a/atomic_qt_design/qml/NoConnection.qml +++ b/atomic_qt_design/qml/NoConnection.qml @@ -12,20 +12,34 @@ Rectangle { color: Style.colorTheme8 ColumnLayout { + spacing: 20 anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter + DefaultText { text_value: API.get().empty_string + (qsTr("No connection")) Layout.alignment: Qt.AlignHCenter font.pixelSize: Style.textSize3 } - DefaultBusyIndicator { + DefaultText { + text_value: API.get().empty_string + (qsTr("Please make sure you are connected to the internet")) Layout.alignment: Qt.AlignHCenter } + DefaultText { - text_value: API.get().empty_string + (qsTr("Please make sure you are connected to the internet")) + text_value: API.get().empty_string + (qsTr("Will automatically retry in %1 seconds").arg(General.formatDouble(API.get().internet_checker.seconds_left_to_auto_retry, 0))) + Layout.alignment: Qt.AlignHCenter + } + + DefaultBusyIndicator { + Layout.alignment: Qt.AlignHCenter + } + + DefaultButton { + text: API.get().empty_string + (qsTr("Retry")) + onClicked: API.get().internet_checker.retry() Layout.alignment: Qt.AlignHCenter } } From e4ad9d8358c7882ead557e7baaa5f6f0a81b1d82 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Tue, 4 Aug 2020 15:27:42 +0200 Subject: [PATCH 163/515] feat(dpow_conf): add backend for dpow confs --- src/atomic.dex.app.cpp | 23 +++++++++++++---------- src/atomic.dex.app.hpp | 4 ++-- src/atomic.dex.mm2.api.cpp | 17 ++++++++++++++++- src/atomic.dex.mm2.api.hpp | 32 ++++++++++++++++++-------------- 4 files changed, 49 insertions(+), 27 deletions(-) diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index fcfa2c6e8c..01c5500e8b 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -278,13 +278,13 @@ namespace atomic_dex case action::post_process_orders_finished: if (mm2.is_mm2_running()) { - qobject_cast(m_manager_models.at("orders"))->refresh_or_insert_orders(); + qobject_cast(m_manager_models.at("orders"))->refresh_or_insert_orders(); } break; case action::post_process_swaps_finished: if (mm2.is_mm2_running()) { - qobject_cast(m_manager_models.at("orders"))->refresh_or_insert_swaps(); + qobject_cast(m_manager_models.at("orders"))->refresh_or_insert_swaps(); } break; case action::post_process_orderbook_finished: @@ -409,8 +409,7 @@ namespace atomic_dex {"addressbook", new addressbook_model(this->m_wallet_manager, this)}, {"portfolio", new portfolio_model(this->system_manager_, this->m_config, this)}, {"orders", new orders_model(this->system_manager_, this)}}, - m_candlestick_chart_ohlc(new candlestick_charts_model(this->system_manager_, this)), - m_orderbook(new qt_orderbook_wrapper(this->system_manager_, this)), + m_candlestick_chart_ohlc(new candlestick_charts_model(this->system_manager_, this)), m_orderbook(new qt_orderbook_wrapper(this->system_manager_, this)), m_internet_service_checker(std::addressof(system_manager_.create_system(this))) { get_dispatcher().sink().connect<&application::on_refresh_update_status_event>(*this); @@ -659,7 +658,7 @@ namespace atomic_dex QString application::place_buy_order( const QString& base, const QString& rel, const QString& price, const QString& volume, bool is_created_order, const QString& price_denom, - const QString& price_numer) + const QString& price_numer, const QString& base_nota, const QString& base_confs) { t_float_50 price_f; t_float_50 amount_f; @@ -676,7 +675,9 @@ namespace atomic_dex .volume = volume.toStdString(), .is_created_order = is_created_order, .price_denom = price_denom.toStdString(), - .price_numer = price_numer.toStdString()}; + .price_numer = price_numer.toStdString(), + .base_nota = base_nota.isEmpty() ? std::optional{std::nullopt} : boost::lexical_cast(base_nota.toStdString()), + .base_confs = base_confs.isEmpty() ? std::optional{std::nullopt} : base_confs.toUInt()}; std::error_code ec; auto answer = get_mm2().place_buy_order(std::move(req), total_amount, ec); @@ -690,7 +691,7 @@ namespace atomic_dex QString application::place_sell_order( const QString& base, const QString& rel, const QString& price, const QString& volume, bool is_created_order, const QString& price_denom, - const QString& price_numer) + const QString& price_numer, const QString& rel_nota, const QString& rel_confs) { qDebug() << " base: " << base << " rel: " << rel << " price: " << price << " volume: " << volume; t_float_50 amount_f; @@ -703,7 +704,9 @@ namespace atomic_dex .volume = volume.toStdString(), .is_created_order = is_created_order, .price_denom = price_denom.toStdString(), - .price_numer = price_numer.toStdString()}; + .price_numer = price_numer.toStdString(), + .rel_nota = rel_nota.isEmpty() ? std::optional{std::nullopt} : boost::lexical_cast(rel_nota.toStdString()), + .rel_confs = rel_confs.isEmpty() ? std::optional{std::nullopt} : rel_confs.toUInt()}; std::error_code ec; auto answer = get_mm2().place_sell_order(std::move(req), amount_f, ec); @@ -855,7 +858,7 @@ namespace atomic_dex portfolio->removeRows(0, count, QModelIndex()); } - orders_model* orders = qobject_cast(m_manager_models.at("orders")); + orders_model* orders = qobject_cast(m_manager_models.at("orders")); if (auto count = orders->rowCount(QModelIndex()); count > 0) { orders->removeRows(0, count, QModelIndex()); @@ -1348,7 +1351,7 @@ namespace atomic_dex orders_model* application::get_orders() const noexcept { - return qobject_cast(m_manager_models.at("orders")); + return qobject_cast(m_manager_models.at("orders")); } } // namespace atomic_dex diff --git a/src/atomic.dex.app.hpp b/src/atomic.dex.app.hpp index 9093b3ced1..6d59cc816a 100644 --- a/src/atomic.dex.app.hpp +++ b/src/atomic.dex.app.hpp @@ -236,10 +236,10 @@ namespace atomic_dex Q_INVOKABLE static QString get_price_amount(const QString& base_amount, const QString& rel_amount); Q_INVOKABLE QString place_buy_order( const QString& base, const QString& rel, const QString& price, const QString& volume, bool is_created_order, const QString& price_denom, - const QString& price_numer); + const QString& price_numer, const QString& base_nota = "", const QString& base_confs = ""); Q_INVOKABLE QString place_sell_order( const QString& base, const QString& rel, const QString& price, const QString& volume, bool is_created_order, const QString& price_denom, - const QString& price_numer); + const QString& price_numer, const QString& rel_nota = "", const QString& rel_confs = ""); Q_INVOKABLE void set_current_orderbook(const QString& base, const QString& rel); Q_INVOKABLE bool do_i_have_enough_funds(const QString& ticker, const QString& amount) const; Q_INVOKABLE bool disable_coins(const QStringList& coins); diff --git a/src/atomic.dex.mm2.api.cpp b/src/atomic.dex.mm2.api.cpp index 2b490a3103..04f2283f20 100644 --- a/src/atomic.dex.mm2.api.cpp +++ b/src/atomic.dex.mm2.api.cpp @@ -524,7 +524,14 @@ namespace mm2::api j["price"] = request.price; j["rel"] = request.rel; j["volume"] = request.volume; - + if (request.base_nota.has_value()) + { + j["base_nota"] = request.base_nota.value(); + } + if (request.base_confs.has_value()) + { + j["base_confs"] = request.base_confs.value(); + } if (not request.is_created_order) { spdlog::info( @@ -550,6 +557,14 @@ namespace mm2::api j["rel"] = request.rel; j["volume"] = request.volume; // 7.77 j["price"] = request.price; + if (request.rel_nota.has_value()) + { + j["rel_nota"] = request.rel_nota.value(); + } + if (request.rel_confs.has_value()) + { + j["rel_confs"] = request.rel_confs.value(); + } if (not request.is_created_order) { diff --git a/src/atomic.dex.mm2.api.hpp b/src/atomic.dex.mm2.api.hpp index 59c2703f82..df1a617bb6 100644 --- a/src/atomic.dex.mm2.api.hpp +++ b/src/atomic.dex.mm2.api.hpp @@ -438,13 +438,15 @@ namespace mm2::api struct buy_request { - std::string base; - std::string rel; - std::string price; - std::string volume; - bool is_created_order; - std::string price_denom; - std::string price_numer; + std::string base; + std::string rel; + std::string price; + std::string volume; + bool is_created_order; + std::string price_denom; + std::string price_numer; + std::optional base_nota{std::nullopt}; + std::optional base_confs{std::nullopt}; }; void to_json(nlohmann::json& j, const buy_request& request); @@ -482,13 +484,15 @@ namespace mm2::api struct sell_request { - std::string base; - std::string rel; - std::string price; - std::string volume; - bool is_created_order; - std::string price_denom; - std::string price_numer; + std::string base; + std::string rel; + std::string price; + std::string volume; + bool is_created_order; + std::string price_denom; + std::string price_numer; + std::optional rel_nota; + std::optional rel_confs; }; void to_json(nlohmann::json& j, const sell_request& request); From 0d1d489822b9ca4f0cf5692a28c187edc3b156f7 Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 4 Aug 2020 17:53:55 +0300 Subject: [PATCH 164/515] feat(gui): add dpow and normal configurations --- .../qml/Exchange/Trade/ConfirmTradeModal.qml | 86 ++++++++++++++++++- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 20 ++++- 2 files changed, 101 insertions(+), 5 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml index b483bdc41c..891d95a246 100644 --- a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml +++ b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml @@ -11,6 +11,12 @@ DefaultModal { width: 1100 + onOpened: reset() + + function reset() { + + } + // Inside modal ColumnLayout { id: modal_layout @@ -79,6 +85,74 @@ DefaultModal { } } + ColumnLayout { + Layout.bottomMargin: 10 + Layout.alignment: Qt.AlignHCenter + + // dPoW configuration switch + Switch { + Layout.alignment: Qt.AlignHCenter + id: enable_dpow_confs + text: API.get().empty_string + (qsTr("Enable dPoW Configurations")) + + onCheckedChanged: { + if(checked) enable_normal_confs.checked = true + } + } + + // dPoW configuration settings + ColumnLayout { + Layout.alignment: Qt.AlignHCenter + Layout.leftMargin: 40 + id: dpow_configurations + visible: enable_dpow_confs.checked + + DefaultCheckBox { + id: enable_notarization + text: API.get().empty_string + (qsTr("Enable Notarization")) + } + } + + // Normal configuration switch + Switch { + Layout.alignment: Qt.AlignHCenter + id: enable_normal_confs + + enabled: !enable_dpow_confs.checked + text: API.get().empty_string + (qsTr("Enable Normal Configurations")) + } + + // Normal configuration settings + ColumnLayout { + Layout.alignment: Qt.AlignHCenter + visible: !enable_dpow_confs.checked && enable_normal_confs.checked + Layout.leftMargin: dpow_configurations.Layout.leftMargin + + DefaultText { + Layout.alignment: Qt.AlignHCenter + text_value: API.get().empty_string + (qsTr("Confirmations") + ": " + required_confirmation_count.value) + } + + Slider { + Layout.alignment: Qt.AlignHCenter + id: required_confirmation_count + stepSize: 1 + from: 1 + to: 5 + live: true + snapMode: Slider.SnapAlways + } + } + + // Warning when both are off + DefaultText { + visible: !enable_dpow_confs.checked && !enable_normal_confs.checked + Layout.alignment: Qt.AlignHCenter + text_value: API.get().empty_string + (qsTr("Warning, this atomic swap is not dPoW/blockchain confirmation protected")) + color: Style.colorRed + } + } + // Buttons RowLayout { DefaultButton { @@ -93,7 +167,17 @@ DefaultModal { onClicked: { root.close() - trade(getTicker(true), getTicker(false)) + trade(getTicker(true), getTicker(false), { + enable_dpow_confs: enable_dpow_confs.enabled && enable_dpow_confs.checked, + dpow_configuration: { + enable_notarization: enable_notarization.checked + }, + + enable_normal_confs: enable_normal_confs.enabled && enable_normal_confs.checked, + normal_configuration: { + required_confirmation_count: required_confirmation_count.value + }, + }) } } } diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index 47f1a6de39..c25de8b1eb 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -269,9 +269,19 @@ Item { } } - function trade(base, rel) { + function trade(base, rel, options) { updateTradeInfo(true) // Force update trade info and cap the value for one last time + let nota = "" + if(options.enable_dpow_confs) { + nota = options.dpow_configuration.enable_notarization ? "1" : "0" + } + + let confs = "" + if(options.enable_normal_confs) { + confs = options.normal_configuration.required_confirmation_count.toString() + } + const current_form = getCurrentForm() const is_created_order = !orderIsSelected() @@ -279,16 +289,18 @@ Item { const price_numer = preffered_order.price_numer const price = getCurrentPrice() const volume = current_form.field.text + console.log("QML place order: nota:", nota, ) console.log("QML place order: max balance:", current_form.getMaxVolume()) - console.log("QML place order: params:", base, " <-> ", rel, " / price:", price, " / volume:", volume, " / is_created_order:", is_created_order, " / price_denom:", price_denom, " / price_numer:", price_numer) + console.log("QML place order: params:", base, " <-> ", rel, " / price:", price, " / volume:", volume, " / is_created_order:", is_created_order, " / price_denom:", price_denom, " / price_numer:", price_numer, + " / nota:", nota, " / confs:", confs) console.log("QML place order: trade info:", JSON.stringify(curr_trade_info)) let result if(sell_mode) - result = API.get().place_sell_order(base, rel, price, volume, is_created_order, price_denom, price_numer) + result = API.get().place_sell_order(base, rel, price, volume, is_created_order, price_denom, price_numer, nota, confs) else - result = API.get().place_buy_order(base, rel, price, volume, is_created_order, price_denom, price_numer) + result = API.get().place_buy_order(base, rel, price, volume, is_created_order, price_denom, price_numer, nota, confs) if(result === "") { action_result = "success" From 9e32a346770f8fe3f72e78642cf4c4b1e8f246d6 Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 4 Aug 2020 18:00:21 +0300 Subject: [PATCH 165/515] feat(gui): recommend confirmation count 3 --- atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml index 891d95a246..693251affc 100644 --- a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml +++ b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml @@ -130,10 +130,13 @@ DefaultModal { DefaultText { Layout.alignment: Qt.AlignHCenter - text_value: API.get().empty_string + (qsTr("Confirmations") + ": " + required_confirmation_count.value) + text_value: API.get().empty_string + (qsTr("Confirmations") + ": " + required_confirmation_count.value + + (required_confirmation_count.value === required_confirmation_count.default_confirmation_count ? + " (" + qsTr("Recommended") + ")" : "")) } Slider { + readonly property int default_confirmation_count: 3 Layout.alignment: Qt.AlignHCenter id: required_confirmation_count stepSize: 1 @@ -141,6 +144,7 @@ DefaultModal { to: 5 live: true snapMode: Slider.SnapAlways + value: default_confirmation_count } } From 9a070971c496eccc35d67436f5f6db8a8a1a25c1 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Tue, 4 Aug 2020 17:09:16 +0200 Subject: [PATCH 166/515] feat(logs): remove log of refresh transactions --- src/atomic.dex.app.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index 01c5500e8b..529004fe6d 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -339,7 +339,6 @@ namespace atomic_dex application::refresh_transactions(const mm2& mm2) { const auto ticker = m_coin_info->get_ticker().toStdString(); - spdlog::debug("{} l{} for coin {}", __FUNCTION__, __LINE__, ticker); std::error_code ec; auto txs = mm2.get_tx_history(ticker, ec); if (!ec) @@ -676,8 +675,8 @@ namespace atomic_dex .is_created_order = is_created_order, .price_denom = price_denom.toStdString(), .price_numer = price_numer.toStdString(), - .base_nota = base_nota.isEmpty() ? std::optional{std::nullopt} : boost::lexical_cast(base_nota.toStdString()), - .base_confs = base_confs.isEmpty() ? std::optional{std::nullopt} : base_confs.toUInt()}; + .base_nota = base_nota.isEmpty() ? std::optional{std::nullopt} : boost::lexical_cast(base_nota.toStdString()), + .base_confs = base_confs.isEmpty() ? std::optional{std::nullopt} : base_confs.toUInt()}; std::error_code ec; auto answer = get_mm2().place_buy_order(std::move(req), total_amount, ec); @@ -705,8 +704,8 @@ namespace atomic_dex .is_created_order = is_created_order, .price_denom = price_denom.toStdString(), .price_numer = price_numer.toStdString(), - .rel_nota = rel_nota.isEmpty() ? std::optional{std::nullopt} : boost::lexical_cast(rel_nota.toStdString()), - .rel_confs = rel_confs.isEmpty() ? std::optional{std::nullopt} : rel_confs.toUInt()}; + .rel_nota = rel_nota.isEmpty() ? std::optional{std::nullopt} : boost::lexical_cast(rel_nota.toStdString()), + .rel_confs = rel_confs.isEmpty() ? std::optional{std::nullopt} : rel_confs.toUInt()}; std::error_code ec; auto answer = get_mm2().place_sell_order(std::move(req), amount_f, ec); From 8bde235ef45aedd4d5ac16bd4210c4bc7d4c7dfe Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 4 Aug 2020 18:37:58 +0300 Subject: [PATCH 167/515] feat(gui): add show() back --- atomic_qt_design/qml/Dashboard/NotificationsPanel.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml index 26497d05a9..39bc9427a6 100644 --- a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml +++ b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml @@ -14,6 +14,7 @@ FloatingBackground { } function showApp() { + window.show() window.raise() window.requestActivate() } From e202db6b6fac388a5506e9e0ef84b9a7605e6e4c Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 4 Aug 2020 19:46:45 +0300 Subject: [PATCH 168/515] feat(gui): add notifications list --- .../qml/Dashboard/NotificationsPanel.qml | 86 +++++++++++++++++-- atomic_qt_design/qml/Screens/Dashboard.qml | 4 +- 2 files changed, 79 insertions(+), 11 deletions(-) diff --git a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml index 39bc9427a6..33e11e51f7 100644 --- a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml +++ b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml @@ -9,6 +9,8 @@ import "../Components" FloatingBackground { id: root + property var notifications_list: ([]) + function reset() { visible = false } @@ -30,7 +32,13 @@ FloatingBackground { // Events function onSwapStatusUpdated(old_swap_status, new_swap_status, swap_uuid) { // TODO: Add qsTr texts for statuses - displayMessage(qsTr("Swap status updated"), old_swap_status + " " + General.right_arrow_icon + " " + new_swap_status) + const obj = { + title: qsTr("Swap status updated"), + message: old_swap_status + " " + General.right_arrow_icon + " " + new_swap_status + } + + notifications_list = [obj].concat(notifications_list) + displayMessage(obj.title, obj.message) } @@ -60,6 +68,9 @@ FloatingBackground { ColumnLayout { anchors.fill: parent anchors.margins: 40 + + spacing: 10 + DefaultText { text_value: API.get().empty_string + (qsTr("Notifications")) Layout.alignment: Qt.AlignLeft | Qt.AlignTop @@ -71,18 +82,75 @@ FloatingBackground { Layout.fillWidth: true } - DefaultButton { - text: API.get().empty_string + (qsTr("Pop Notification")) - Layout.alignment: Qt.AlignTop - onClicked: { - onSwapStatusUpdated("ongoing", "finished", "123456") + InnerBackground { + Layout.fillWidth: true + Layout.fillHeight: true + + DefaultText { + anchors.centerIn: parent + visible: !list.visible + text_value: API.get().empty_string + (qsTr("There isn't any notification")) + font.pixelSize: Style.textSizeSmall2 + } + + DefaultListView { + id: list + + visible: notifications_list.length !== 0 + + anchors.fill: parent + model: notifications_list + + delegate: Item { + width: list.width + height: 60 + + ColumnLayout { + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: 10 + + DefaultText { + text_value: API.get().empty_string + (modelData.title) + font.pixelSize: Style.textSizeSmall4 + } + + DefaultText { + text_value: API.get().empty_string + (modelData.message) + font.pixelSize: Style.textSizeSmall1 + } + } + + HorizontalLine { + visible: index !== notifications_list.length - 1 + width: parent.width - 4 + + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + anchors.bottomMargin: -height/2 + light: true + } + } } } - DefaultButton { - text: API.get().empty_string + (qsTr("Close")) + + RowLayout { Layout.alignment: Qt.AlignBottom - onClicked: root.visible = false + Layout.bottomMargin: parent.spacing + spacing: 10 + + DefaultButton { + text: API.get().empty_string + (qsTr("Pop Notification")) + onClicked: { + onSwapStatusUpdated("ongoing", "finished", "123456") + } + } + + DefaultButton { + text: API.get().empty_string + (qsTr("Close")) + onClicked: root.visible = false + } } } } diff --git a/atomic_qt_design/qml/Screens/Dashboard.qml b/atomic_qt_design/qml/Screens/Dashboard.qml index 45db8b99f4..f036631ee0 100644 --- a/atomic_qt_design/qml/Screens/Dashboard.qml +++ b/atomic_qt_design/qml/Screens/Dashboard.qml @@ -133,8 +133,8 @@ Item { NotificationsPanel { id: notifications_panel - width: 300 - height: 600 + width: 500 + height: 500 anchors.left: sidebar.right anchors.bottom: parent.bottom anchors.bottomMargin: -40 From 07b6d17d7325886890db483ca969dc60498d844a Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 4 Aug 2020 19:53:29 +0300 Subject: [PATCH 169/515] feat(gui): add full texts of swap status --- atomic_qt_design/qml/Dashboard/NotificationsPanel.qml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml index 33e11e51f7..f21c30e775 100644 --- a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml +++ b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml @@ -31,10 +31,9 @@ FloatingBackground { // Events function onSwapStatusUpdated(old_swap_status, new_swap_status, swap_uuid) { - // TODO: Add qsTr texts for statuses const obj = { title: qsTr("Swap status updated"), - message: old_swap_status + " " + General.right_arrow_icon + " " + new_swap_status + message: exchange.getStatusText(old_swap_status) + " " + General.right_arrow_icon + " " + exchange.getStatusText(new_swap_status) } notifications_list = [obj].concat(notifications_list) @@ -113,6 +112,7 @@ FloatingBackground { DefaultText { text_value: API.get().empty_string + (modelData.title) font.pixelSize: Style.textSizeSmall4 + font.bold: true } DefaultText { @@ -141,7 +141,7 @@ FloatingBackground { spacing: 10 DefaultButton { - text: API.get().empty_string + (qsTr("Pop Notification")) + text: API.get().empty_string + (qsTr("Pop Test Notification")) onClicked: { onSwapStatusUpdated("ongoing", "finished", "123456") } From 996e10dfa07e5c1703568b9e1450ca760f70bc3e Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 4 Aug 2020 20:54:35 +0300 Subject: [PATCH 170/515] feat(gui): add unread notification count --- .../qml/Dashboard/NotificationsPanel.qml | 8 ++++++++ atomic_qt_design/qml/Sidebar/Sidebar.qml | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml index f21c30e775..8b1e9028df 100644 --- a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml +++ b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml @@ -9,6 +9,7 @@ import "../Components" FloatingBackground { id: root + property int unread_notification_count: 0 property var notifications_list: ([]) function reset() { @@ -23,6 +24,10 @@ FloatingBackground { visible: false + onVisibleChanged: { + if(visible) unread_notification_count = 0 + } + MouseArea { anchors.fill: parent preventStealing: true @@ -36,6 +41,9 @@ FloatingBackground { message: exchange.getStatusText(old_swap_status) + " " + General.right_arrow_icon + " " + exchange.getStatusText(new_swap_status) } + if(!root.visible) + ++unread_notification_count + notifications_list = [obj].concat(notifications_list) displayMessage(obj.title, obj.message) } diff --git a/atomic_qt_design/qml/Sidebar/Sidebar.qml b/atomic_qt_design/qml/Sidebar/Sidebar.qml index 30510f69b1..0ad717c150 100644 --- a/atomic_qt_design/qml/Sidebar/Sidebar.qml +++ b/atomic_qt_design/qml/Sidebar/Sidebar.qml @@ -156,6 +156,25 @@ Item { text: "🔔" minWidth: height onClicked: notifications_panel.visible = !notifications_panel.visible + + Rectangle { + radius: 1337 + width: count_text.height * 1.5 + height: width + anchors.horizontalCenter: parent.right + anchors.verticalCenter: parent.bottom + color: Style.colorRed + visible: notifications_panel.unread_notification_count > 0 + + DefaultText { + id: count_text + anchors.centerIn: parent + text_value: notifications_panel.unread_notification_count + font.pixelSize: Style.textSizeSmall1 + font.bold: true + color: Style.colorWhite9 + } + } } SidebarBottom { From f7792d649108eb4db29aff7bc6047de7ffa6b772 Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 4 Aug 2020 20:54:50 +0300 Subject: [PATCH 171/515] feat(gui): add notification date --- .../qml/Dashboard/NotificationsPanel.qml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml index 8b1e9028df..18d4964194 100644 --- a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml +++ b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml @@ -38,7 +38,8 @@ FloatingBackground { function onSwapStatusUpdated(old_swap_status, new_swap_status, swap_uuid) { const obj = { title: qsTr("Swap status updated"), - message: exchange.getStatusText(old_swap_status) + " " + General.right_arrow_icon + " " + exchange.getStatusText(new_swap_status) + message: exchange.getStatusText(old_swap_status) + " " + General.right_arrow_icon + " " + exchange.getStatusText(new_swap_status), + time: Date.now() } if(!root.visible) @@ -112,6 +113,15 @@ FloatingBackground { width: list.width height: 60 + DefaultText { + anchors.top: parent.top + anchors.topMargin: 10 + anchors.right: parent.right + anchors.rightMargin: 30 + text_value: API.get().empty_string + (General.timestampToString(modelData.time)) + font.pixelSize: Style.textSizeSmall + } + ColumnLayout { anchors.verticalCenter: parent.verticalCenter anchors.left: parent.left From bb45b7cca45d4b97a515f94d0f8706e996e3e6ef Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 4 Aug 2020 21:05:07 +0300 Subject: [PATCH 172/515] feat(gui): use toUTCString --- atomic_qt_design/qml/Constants/General.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomic_qt_design/qml/Constants/General.qml b/atomic_qt_design/qml/Constants/General.qml index 7b5d0e32b2..6eef9cae51 100644 --- a/atomic_qt_design/qml/Constants/General.qml +++ b/atomic_qt_design/qml/Constants/General.qml @@ -54,7 +54,7 @@ QtObject { } function timestampToString(timestamp) { - return (new Date(timestamp)).getUTCDate() + return (new Date(timestamp)).toUTCString() } function timestampToDate(timestamp) { From d27f9192145a0b304ab77779fc63520942d97c70 Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 4 Aug 2020 23:10:29 +0300 Subject: [PATCH 173/515] feat(gui): close notification panel on outside click --- .../qml/Components/DefaultButton.qml | 18 +++---- atomic_qt_design/qml/Screens/Dashboard.qml | 53 +++++++++++++++++-- 2 files changed, 59 insertions(+), 12 deletions(-) diff --git a/atomic_qt_design/qml/Components/DefaultButton.qml b/atomic_qt_design/qml/Components/DefaultButton.qml index c4aefa4b06..81bf4fe167 100644 --- a/atomic_qt_design/qml/Components/DefaultButton.qml +++ b/atomic_qt_design/qml/Components/DefaultButton.qml @@ -34,15 +34,6 @@ FloatingBackground { color: !enabled ? colorDisabled : mouse_area.containsMouse ? colorHovered : colorEnabled border.width: 0 - MouseArea { - id: mouse_area - anchors.fill: parent - hoverEnabled: true - onClicked: { - if(parent.enabled) parent.clicked() - } - } - DefaultText { id: text_obj anchors.horizontalCenter: text_left_align ? undefined : parent.horizontalCenter @@ -54,4 +45,13 @@ FloatingBackground { font.capitalization: Font.AllUppercase color: !parent.enabled ? colorTextDisabled : mouse_area.containsMouse ? colorTextHovered : colorTextEnabled } + + MouseArea { + id: mouse_area + anchors.fill: parent + hoverEnabled: true + onClicked: { + if(parent.enabled) parent.clicked() + } + } } diff --git a/atomic_qt_design/qml/Screens/Dashboard.qml b/atomic_qt_design/qml/Screens/Dashboard.qml index f036631ee0..1408b0307f 100644 --- a/atomic_qt_design/qml/Screens/Dashboard.qml +++ b/atomic_qt_design/qml/Screens/Dashboard.qml @@ -131,6 +131,30 @@ Item { } } + // Sidebar, left side + Sidebar { + id: sidebar + } + + // Global click + MouseArea { + anchors.fill: parent + propagateComposedEvents: true + + onClicked: mouse.accepted = false + onReleased: mouse.accepted = false + onPressAndHold: mouse.accepted = false + onDoubleClicked: mouse.accepted = false + onPositionChanged: mouse.accepted = false + onPressed: { + // Close notifications panel on outside click + if(notifications_panel.visible) + notifications_panel.visible = false + + mouse.accepted = false + } + } + NotificationsPanel { id: notifications_panel width: 500 @@ -140,9 +164,32 @@ Item { anchors.bottomMargin: -40 } - // Sidebar, left side - Sidebar { - id: sidebar + DefaultButton { + anchors.horizontalCenter: sidebar.horizontalCenter + anchors.bottom: sidebar.bottom + anchors.bottomMargin: 150 + text: "🔔" + minWidth: height + onClicked: notifications_panel.visible = !notifications_panel.visible + + Rectangle { + radius: 1337 + width: count_text.height * 1.5 + height: width + anchors.horizontalCenter: parent.right + anchors.verticalCenter: parent.bottom + color: Style.colorRed + visible: notifications_panel.unread_notification_count > 0 + + DefaultText { + id: count_text + anchors.centerIn: parent + text_value: notifications_panel.unread_notification_count + font.pixelSize: Style.textSizeSmall1 + font.bold: true + color: Style.colorWhite9 + } + } } DropShadow { From 93faf4a9d2eb3e199a56eedf7cf31f8c1c1d78ab Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 4 Aug 2020 23:12:28 +0300 Subject: [PATCH 174/515] feat(gui): cleanup --- atomic_qt_design/qml/Sidebar/Sidebar.qml | 28 ------------------------ 1 file changed, 28 deletions(-) diff --git a/atomic_qt_design/qml/Sidebar/Sidebar.qml b/atomic_qt_design/qml/Sidebar/Sidebar.qml index 0ad717c150..6175874e98 100644 --- a/atomic_qt_design/qml/Sidebar/Sidebar.qml +++ b/atomic_qt_design/qml/Sidebar/Sidebar.qml @@ -149,34 +149,6 @@ Item { anchors.verticalCenter: parent.verticalCenter } - DefaultButton { - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: sidebar_bottom.top - anchors.bottomMargin: 25 - text: "🔔" - minWidth: height - onClicked: notifications_panel.visible = !notifications_panel.visible - - Rectangle { - radius: 1337 - width: count_text.height * 1.5 - height: width - anchors.horizontalCenter: parent.right - anchors.verticalCenter: parent.bottom - color: Style.colorRed - visible: notifications_panel.unread_notification_count > 0 - - DefaultText { - id: count_text - anchors.centerIn: parent - text_value: notifications_panel.unread_notification_count - font.pixelSize: Style.textSizeSmall1 - font.bold: true - color: Style.colorWhite9 - } - } - } - SidebarBottom { id: sidebar_bottom width: parent.width From b298262aa28fdb90b6b3ed4d30b2e044215be521 Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 4 Aug 2020 23:27:45 +0300 Subject: [PATCH 175/515] feat(gui): fix notification button was behind the sidebar --- atomic_qt_design/qml/Screens/Dashboard.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/atomic_qt_design/qml/Screens/Dashboard.qml b/atomic_qt_design/qml/Screens/Dashboard.qml index 1408b0307f..3d778dd182 100644 --- a/atomic_qt_design/qml/Screens/Dashboard.qml +++ b/atomic_qt_design/qml/Screens/Dashboard.qml @@ -168,6 +168,7 @@ Item { anchors.horizontalCenter: sidebar.horizontalCenter anchors.bottom: sidebar.bottom anchors.bottomMargin: 150 + z: 1 text: "🔔" minWidth: height onClicked: notifications_panel.visible = !notifications_panel.visible From faf72505d3a9dc2c0947c5458b73e5d66a4991a4 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Wed, 5 Aug 2020 07:45:17 +0200 Subject: [PATCH 176/515] enhancements(app): clean code app cpp/hpp --- src/atomic.dex.app.cpp | 50 +++++++++++++++++++++--------------------- src/atomic.dex.app.hpp | 7 ++---- 2 files changed, 27 insertions(+), 30 deletions(-) diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index a99fab393a..b66926f123 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -252,14 +252,13 @@ namespace atomic_dex case action::refresh_ohlc: if (mm2.is_mm2_running()) { - // emit OHLCDataUpdated(); if (this->m_candlestick_need_a_reset) { - this->m_candlestick_chart_ohlc->init_data(); + qobject_cast(m_manager_models.at("candlesticks"))->init_data(); } else { - this->m_candlestick_chart_ohlc->update_data(); + qobject_cast(m_manager_models.at("candlesticks"))->update_data(); } } break; @@ -291,16 +290,16 @@ namespace atomic_dex if (mm2.is_mm2_running()) { std::error_code ec; - t_orderbook_answer result = this->get_mm2().get_orderbook(ec); + t_orderbook_answer result = get_mm2().get_orderbook(ec); if (!ec) { - if (this->m_orderbook_need_a_reset) + if (m_orderbook_need_a_reset) { - this->m_orderbook->reset_orderbook(result); + qobject_cast(m_manager_models.at("orderbook"))->reset_orderbook(result); } else { - this->m_orderbook->refresh_orderbook(result); + qobject_cast(m_manager_models.at("orderbook"))->refresh_orderbook(result); } } } @@ -404,14 +403,15 @@ namespace atomic_dex QObject(pParent), m_update_status(QJsonObject{ {"update_needed", false}, {"changelog", ""}, {"current_version", ""}, {"download_url", ""}, {"new_version", ""}, {"rpc_code", 0}, {"status", ""}}), - m_coin_info(new current_coin_info(dispatcher_, this)), - m_manager_models{ - {"addressbook", new addressbook_model(this->m_wallet_manager, this)}, - {"portfolio", new portfolio_model(this->system_manager_, this->m_config, this)}, - {"orders", new orders_model(this->system_manager_, this->dispatcher_, this)}}, - m_candlestick_chart_ohlc(new candlestick_charts_model(this->system_manager_, this)), m_orderbook(new qt_orderbook_wrapper(this->system_manager_, this)), - m_internet_service_checker(std::addressof(system_manager_.create_system(this))), - m_notification_manager(new notification_manager(this->dispatcher_, this)) + m_coin_info(new current_coin_info(dispatcher_, this)), m_manager_models{ + {"addressbook", new addressbook_model(this->m_wallet_manager, this)}, + {"portfolio", new portfolio_model(this->system_manager_, this->m_config, this)}, + {"orders", new orders_model(this->system_manager_, this->dispatcher_, this)}, + {"candlesticks", new candlestick_charts_model(this->system_manager_, this)}, + {"orderbook", new qt_orderbook_wrapper(this->system_manager_, this)}, + {"internet_service", + std::addressof(system_manager_.create_system(this))}, + {"notifications", new notification_manager(this->dispatcher_, this)}} { get_dispatcher().sink().connect<&application::on_refresh_update_status_event>(*this); //! MM2 system need to be created before the GUI and give the instance to the gui @@ -789,7 +789,7 @@ namespace atomic_dex { auto& provider = this->system_manager_.get_system(); auto [normal, quoted] = provider.is_pair_supported(base.toStdString(), rel.toStdString()); - this->m_candlestick_chart_ohlc->set_is_pair_supported(normal || quoted); + qobject_cast(m_manager_models.at("candlesticks"))->set_is_pair_supported(normal || quoted); this->dispatcher_.trigger(base.toStdString(), rel.toStdString()); } @@ -861,8 +861,8 @@ namespace atomic_dex orders->removeRows(0, count, QModelIndex()); } orders->clear_registry(); - this->m_candlestick_chart_ohlc->clear_data(); - this->m_orderbook->clear_orderbook(); + qobject_cast(m_manager_models.at("candlesticks"))->clear_data(); + qobject_cast(m_manager_models.at("orderbook"))->clear_orderbook(); //! Mark systems system_manager_.mark_system(); @@ -870,7 +870,7 @@ namespace atomic_dex system_manager_.mark_system(); //! Disconnect signals - this->m_notification_manager->disconnect_signals(); + qobject_cast(m_manager_models.at("notifications"))->disconnect_signals(); get_dispatcher().sink().disconnect<&application::on_ticker_balance_updated_event>(*this); get_dispatcher().sink().disconnect<&application::on_change_ticker_event>(*this); get_dispatcher().sink().disconnect<&application::on_enabled_coins_event>(*this); @@ -897,7 +897,7 @@ namespace atomic_dex application::connect_signals() { spdlog::debug("{} l{}", __FUNCTION__, __LINE__); - this->m_notification_manager->connect_signals(); + qobject_cast(m_manager_models.at("notifications"))->connect_signals(); get_dispatcher().sink().connect<&application::on_ticker_balance_updated_event>(*this); get_dispatcher().sink().connect<&application::on_change_ticker_event>(*this); get_dispatcher().sink().connect<&application::on_enabled_coins_event>(*this); @@ -1268,7 +1268,7 @@ namespace atomic_dex candlestick_charts_model* application::get_candlestick_charts() const noexcept { - return m_candlestick_chart_ohlc; + return qobject_cast(m_manager_models.at("candlesticks")); } QVariantMap @@ -1497,7 +1497,7 @@ namespace atomic_dex void application::on_start_fetching_new_ohlc_data_event(const start_fetching_new_ohlc_data& evt) { - this->m_candlestick_chart_ohlc->set_is_currently_fetching(evt.is_a_reset); + qobject_cast(m_manager_models.at("candlesticks"))->set_is_currently_fetching(evt.is_a_reset); } } // namespace atomic_dex @@ -1507,7 +1507,7 @@ namespace atomic_dex qt_orderbook_wrapper* application::get_orderbook_wrapper() const noexcept { - return m_orderbook; + return qobject_cast(m_manager_models.at("orderbook")); } void @@ -1527,7 +1527,7 @@ namespace atomic_dex notification_manager* application::get_notification_manager() const noexcept { - return m_notification_manager; + return qobject_cast(m_manager_models.at("notifications")); } } // namespace atomic_dex @@ -1537,6 +1537,6 @@ namespace atomic_dex internet_service_checker* application::get_internet_checker() const noexcept { - return m_internet_service_checker; + return qobject_cast(m_manager_models.at("internet_service")); } } // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.app.hpp b/src/atomic.dex.app.hpp index 38de1c6a9c..dac7c662e5 100644 --- a/src/atomic.dex.app.hpp +++ b/src/atomic.dex.app.hpp @@ -110,7 +110,6 @@ namespace atomic_dex atomic_dex::qt_wallet_manager m_wallet_manager; t_actions_queue m_actions_queue{g_max_actions_size}; t_synchronized_string m_ticker_balance_to_refresh; - bool m_need_a_full_refresh_of_mm2{false}; QVariantList m_enabled_coins; QVariantList m_enableable_coins; QVariant m_update_status; @@ -120,13 +119,11 @@ namespace atomic_dex QString m_current_balance_all{"0.00"}; current_coin_info* m_coin_info; t_manager_model_registry m_manager_models; - candlestick_charts_model* m_candlestick_chart_ohlc; + std::atomic_bool m_need_a_full_refresh_of_mm2{false}; std::atomic_bool m_candlestick_need_a_reset{false}; - qt_orderbook_wrapper* m_orderbook; std::atomic_bool m_orderbook_need_a_reset{false}; - internet_service_checker* m_internet_service_checker; std::atomic_bool m_about_to_exit_app{false}; - notification_manager* m_notification_manager; + //notification_manager* m_notification_manager; public: //! Constructor From 8a4d4baabba3b10eb431f9fe97d89fa05c2615a0 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Wed, 5 Aug 2020 08:11:47 +0200 Subject: [PATCH 177/515] enhancements(code): coontinue code cleaniing --- src/atomic.dex.app.cpp | 45 +++++++++++++++++++++--------------------- src/atomic.dex.app.hpp | 37 +++++++++++++++++++--------------- 2 files changed, 43 insertions(+), 39 deletions(-) diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index b66926f123..18e1c1f0d5 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -195,14 +195,14 @@ namespace atomic_dex application::tick() { this->process_one_frame(); - if (this->m_need_a_full_refresh_of_mm2) + if (m_event_actions[events_action::need_a_full_refresh_of_mm2]) { auto& mm2_s = system_manager_.create_system(); system_manager_.create_system(mm2_s, m_config); system_manager_.create_system(mm2_s); connect_signals(); - this->m_need_a_full_refresh_of_mm2 = false; + m_event_actions[events_action::need_a_full_refresh_of_mm2] = false; } auto& mm2 = get_mm2(); auto& paprika = get_paprika(); @@ -210,7 +210,6 @@ namespace atomic_dex { if (m_coin_info->get_ticker().isEmpty() && not m_enabled_coins.empty()) { - // auto coin = mm2.get_enabled_coins().front(); //! KMD Is our default coin m_coin_info->set_ticker("KMD"); emit coinInfoChanged(); @@ -231,7 +230,7 @@ namespace atomic_dex } } - if (not this->m_actions_queue.empty() && not this->m_about_to_exit_app) + if (not this->m_actions_queue.empty() && not m_event_actions[events_action::about_to_exit_app]) { action last_action; this->m_actions_queue.pop(last_action); @@ -252,7 +251,7 @@ namespace atomic_dex case action::refresh_ohlc: if (mm2.is_mm2_running()) { - if (this->m_candlestick_need_a_reset) + if (m_event_actions[events_action::candlestick_need_a_reset]) { qobject_cast(m_manager_models.at("candlesticks"))->init_data(); } @@ -293,7 +292,7 @@ namespace atomic_dex t_orderbook_answer result = get_mm2().get_orderbook(ec); if (!ec) { - if (m_orderbook_need_a_reset) + if (m_event_actions[events_action::orderbook_need_a_reset]) { qobject_cast(m_manager_models.at("orderbook"))->reset_orderbook(result); } @@ -465,7 +464,7 @@ namespace atomic_dex atomic_dex::application::on_enabled_coins_event([[maybe_unused]] const enabled_coins_event& evt) noexcept { spdlog::debug("{} l{}", __FUNCTION__, __LINE__); - if (not m_about_to_exit_app) + if (not m_event_actions[events_action::about_to_exit_app]) { this->m_actions_queue.push(action::refresh_enabled_coin); } @@ -475,7 +474,7 @@ namespace atomic_dex application::on_enabled_default_coins_event([[maybe_unused]] const enabled_default_coins_event& evt) noexcept { spdlog::debug("{} l{}", __FUNCTION__, __LINE__); - if (not m_about_to_exit_app) + if (not m_event_actions[events_action::about_to_exit_app]) { this->m_actions_queue.push(action::refresh_enabled_coin); } @@ -542,7 +541,7 @@ namespace atomic_dex application::on_change_ticker_event([[maybe_unused]] const change_ticker_event& evt) noexcept { spdlog::debug("{} l{}", __FUNCTION__, __LINE__); - if (not m_about_to_exit_app) + if (not m_event_actions[events_action::about_to_exit_app]) { this->m_actions_queue.push(action::refresh_current_ticker); } @@ -624,7 +623,7 @@ namespace atomic_dex atomic_dex::t_broadcast_request req{.tx_hex = tx_hex.toStdString(), .coin = m_coin_info->get_ticker().toStdString()}; std::error_code ec; auto answer = get_mm2().broadcast(std::move(req), ec); - if (not m_about_to_exit_app) + if (not m_event_actions[events_action::about_to_exit_app]) { this->m_actions_queue.push(action::refresh_current_ticker); } @@ -638,7 +637,7 @@ namespace atomic_dex atomic_dex::t_broadcast_request req{.tx_hex = tx_hex.toStdString(), .coin = m_coin_info->get_ticker().toStdString()}; std::error_code ec; auto answer = get_mm2().send_rewards(std::move(req), ec); - if (not m_about_to_exit_app) + if (not m_event_actions[events_action::about_to_exit_app]) { this->m_actions_queue.push(action::refresh_current_ticker); } @@ -650,7 +649,7 @@ namespace atomic_dex application::on_tx_fetch_finished_event([[maybe_unused]] const tx_fetch_finished& evt) noexcept { spdlog::debug("{} l{}", __FUNCTION__, __LINE__); - if (not m_about_to_exit_app) + if (not m_event_actions[events_action::about_to_exit_app]) { this->m_actions_queue.push(action::refresh_transactions); } @@ -731,7 +730,7 @@ namespace atomic_dex application::on_coin_disabled_event([[maybe_unused]] const coin_disabled& evt) noexcept { spdlog::debug("{} l{}", __FUNCTION__, __LINE__); - if (not m_about_to_exit_app) + if (not m_event_actions[events_action::about_to_exit_app]) { this->m_actions_queue.push(action::refresh_enabled_coin); } @@ -797,7 +796,7 @@ namespace atomic_dex application::on_refresh_update_status_event([[maybe_unused]] const refresh_update_status& evt) noexcept { spdlog::debug("{} l{}", __FUNCTION__, __LINE__); - if (not m_about_to_exit_app) + if (not m_event_actions[events_action::about_to_exit_app]) { this->m_actions_queue.push(action::refresh_update_status); } @@ -886,7 +885,7 @@ namespace atomic_dex get_dispatcher().sink().disconnect<&application::on_process_orderbook_finished_event>(*this); get_dispatcher().sink().disconnect<&application::on_start_fetching_new_ohlc_data_event>(*this); - this->m_need_a_full_refresh_of_mm2 = true; + m_event_actions[events_action::need_a_full_refresh_of_mm2] = true; this->m_wallet_manager.just_set_wallet_name(""); emit onWalletDefaultNameChanged(); @@ -1295,10 +1294,10 @@ namespace atomic_dex application::on_refresh_ohlc_event([[maybe_unused]] const refresh_ohlc_needed& evt) noexcept { spdlog::debug("{} l{}", __FUNCTION__, __LINE__); - if (not m_about_to_exit_app) + if (not m_event_actions[events_action::about_to_exit_app]) { this->m_actions_queue.push(action::refresh_ohlc); - this->m_candlestick_need_a_reset = evt.is_a_reset; + m_event_actions[events_action::candlestick_need_a_reset] = evt.is_a_reset; } } @@ -1306,7 +1305,7 @@ namespace atomic_dex application::on_ticker_balance_updated_event(const ticker_balance_updated& evt) noexcept { spdlog::trace("{} l{}", __FUNCTION__, __LINE__); - if (not m_about_to_exit_app) + if (not m_event_actions[events_action::about_to_exit_app]) { this->m_actions_queue.push(action::refresh_portfolio_ticker_balance); } @@ -1331,7 +1330,7 @@ namespace atomic_dex application::on_process_swaps_finished_event([[maybe_unused]] const process_swaps_finished& evt) noexcept { spdlog::trace("{} l{}", __FUNCTION__, __LINE__); - if (not m_about_to_exit_app) + if (not m_event_actions[events_action::about_to_exit_app]) { this->m_actions_queue.push(action::post_process_swaps_finished); } @@ -1341,7 +1340,7 @@ namespace atomic_dex application::on_process_orders_finished_event([[maybe_unused]] const process_orders_finished& evt) noexcept { spdlog::trace("{} l{}", __FUNCTION__, __LINE__); - if (not m_about_to_exit_app) + if (not m_event_actions[events_action::about_to_exit_app]) { this->m_actions_queue.push(action::post_process_orders_finished); } @@ -1491,7 +1490,7 @@ namespace atomic_dex application::exit_handler() { spdlog::trace("will quit app, prevent all threading event"); - this->m_about_to_exit_app = true; + m_event_actions[events_action::about_to_exit_app] = true; } void @@ -1513,10 +1512,10 @@ namespace atomic_dex void application::on_process_orderbook_finished_event(const process_orderbook_finished& evt) noexcept { - if (not m_about_to_exit_app) + if (not m_event_actions[events_action::about_to_exit_app]) { this->m_actions_queue.push(action::post_process_orderbook_finished); - this->m_orderbook_need_a_reset = evt.is_a_reset; + m_event_actions[events_action::orderbook_need_a_reset] = evt.is_a_reset; } } } // namespace atomic_dex diff --git a/src/atomic.dex.app.hpp b/src/atomic.dex.app.hpp index dac7c662e5..cc0b224fa9 100644 --- a/src/atomic.dex.app.hpp +++ b/src/atomic.dex.app.hpp @@ -99,10 +99,20 @@ namespace atomic_dex post_process_orderbook_finished = 8 }; + enum events_action + { + need_a_full_refresh_of_mm2 = 0, + candlestick_need_a_reset = 1, + orderbook_need_a_reset = 2, + about_to_exit_app = 3, + size = 4 + }; + //! Private typedefs using t_actions_queue = boost::lockfree::queue; using t_synchronized_string = boost::synchronized_value; using t_manager_model_registry = std::unordered_map; + using t_events_actions = std::array; //! Private members fields atomic_dex::cfg m_config{load_cfg()}; @@ -119,11 +129,7 @@ namespace atomic_dex QString m_current_balance_all{"0.00"}; current_coin_info* m_coin_info; t_manager_model_registry m_manager_models; - std::atomic_bool m_need_a_full_refresh_of_mm2{false}; - std::atomic_bool m_candlestick_need_a_reset{false}; - std::atomic_bool m_orderbook_need_a_reset{false}; - std::atomic_bool m_about_to_exit_app{false}; - //notification_manager* m_notification_manager; + t_events_actions m_event_actions{{false}}; public: //! Constructor @@ -148,17 +154,16 @@ namespace atomic_dex void on_start_fetching_new_ohlc_data_event(const start_fetching_new_ohlc_data&); //! Properties Getter - static const QString& get_empty_string(); - mm2& get_mm2() noexcept; - const mm2& get_mm2() const noexcept; - coinpaprika_provider& get_paprika() noexcept; - entt::dispatcher& get_dispatcher() noexcept; - QObject* get_current_coin_info() const noexcept; - addressbook_model* get_addressbook() const noexcept; - portfolio_model* get_portfolio() const noexcept; - orders_model* get_orders() const noexcept; - notification_manager* get_notification_manager() const noexcept; - ; + static const QString& get_empty_string(); + mm2& get_mm2() noexcept; + const mm2& get_mm2() const noexcept; + coinpaprika_provider& get_paprika() noexcept; + entt::dispatcher& get_dispatcher() noexcept; + QObject* get_current_coin_info() const noexcept; + addressbook_model* get_addressbook() const noexcept; + portfolio_model* get_portfolio() const noexcept; + orders_model* get_orders() const noexcept; + notification_manager* get_notification_manager() const noexcept; candlestick_charts_model* get_candlestick_charts() const noexcept; internet_service_checker* get_internet_checker() const noexcept; qt_orderbook_wrapper* get_orderbook_wrapper() const noexcept; From a93340abb966e9f07ab00f0d9a7863ebfc9acb21 Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 5 Aug 2020 14:53:51 +0300 Subject: [PATCH 178/515] feat(gui): change trade config texts --- atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml index 693251affc..bf0b189117 100644 --- a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml +++ b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml @@ -93,7 +93,7 @@ DefaultModal { Switch { Layout.alignment: Qt.AlignHCenter id: enable_dpow_confs - text: API.get().empty_string + (qsTr("Enable dPoW Configurations")) + text: API.get().empty_string + (qsTr("Enable Komodo dPoW security")) onCheckedChanged: { if(checked) enable_normal_confs.checked = true @@ -119,7 +119,7 @@ DefaultModal { id: enable_normal_confs enabled: !enable_dpow_confs.checked - text: API.get().empty_string + (qsTr("Enable Normal Configurations")) + text: API.get().empty_string + (qsTr("Change required confirmations")) } // Normal configuration settings From b2ebb2545744677e41b673394b4b11f8cbb07eba Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 5 Aug 2020 17:17:15 +0300 Subject: [PATCH 179/515] feat(gui): change dpow config section layout --- .../qml/Exchange/Trade/ConfirmTradeModal.qml | 106 +++++++++--------- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 13 ++- 2 files changed, 63 insertions(+), 56 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml index bf0b189117..18084b82e4 100644 --- a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml +++ b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml @@ -89,70 +89,79 @@ DefaultModal { Layout.bottomMargin: 10 Layout.alignment: Qt.AlignHCenter - // dPoW configuration switch - Switch { - Layout.alignment: Qt.AlignHCenter - id: enable_dpow_confs - text: API.get().empty_string + (qsTr("Enable Komodo dPoW security")) - onCheckedChanged: { - if(checked) enable_normal_confs.checked = true - } + // Enable custom config + DefaultCheckBox { + Layout.alignment: Qt.AlignHCenter + id: enable_custom_config + text: API.get().empty_string + (qsTr("Use custom protection settings")) } - // dPoW configuration settings + // Configuration settings ColumnLayout { + id: custom_config + visible: enable_custom_config.checked + Layout.alignment: Qt.AlignHCenter Layout.leftMargin: 40 - id: dpow_configurations - visible: enable_dpow_confs.checked - DefaultCheckBox { - id: enable_notarization - text: API.get().empty_string + (qsTr("Enable Notarization")) - } - } - - // Normal configuration switch - Switch { - Layout.alignment: Qt.AlignHCenter - id: enable_normal_confs + // dPoW configuration switch + Switch { + id: enable_dpow_confs + Layout.alignment: Qt.AlignHCenter - enabled: !enable_dpow_confs.checked - text: API.get().empty_string + (qsTr("Change required confirmations")) - } + checked: true + onCheckedChanged: { + if(checked) enable_normal_confs.checked = true + } - // Normal configuration settings - ColumnLayout { - Layout.alignment: Qt.AlignHCenter - visible: !enable_dpow_confs.checked && enable_normal_confs.checked - Layout.leftMargin: dpow_configurations.Layout.leftMargin + text: API.get().empty_string + (qsTr("Enable Komodo dPoW security")) + } - DefaultText { + // Normal configuration switch + Switch { + id: enable_normal_confs Layout.alignment: Qt.AlignHCenter - text_value: API.get().empty_string + (qsTr("Confirmations") + ": " + required_confirmation_count.value - + (required_confirmation_count.value === required_confirmation_count.default_confirmation_count ? - " (" + qsTr("Recommended") + ")" : "")) + + enabled: !enable_dpow_confs.checked + checked: true + + text: API.get().empty_string + (qsTr("Change required confirmations")) } - Slider { - readonly property int default_confirmation_count: 3 + // Normal configuration settings + ColumnLayout { Layout.alignment: Qt.AlignHCenter - id: required_confirmation_count - stepSize: 1 - from: 1 - to: 5 - live: true - snapMode: Slider.SnapAlways - value: default_confirmation_count + visible: !enable_dpow_confs.checked && enable_normal_confs.checked + Layout.leftMargin: custom_config.Layout.leftMargin + + DefaultText { + Layout.alignment: Qt.AlignHCenter + text_value: API.get().empty_string + (qsTr("Confirmations") + ": " + required_confirmation_count.value + + (required_confirmation_count.value === required_confirmation_count.default_confirmation_count ? + " (" + qsTr("Recommended") + ")" : "")) + } + + Slider { + readonly property int default_confirmation_count: 3 + Layout.alignment: Qt.AlignHCenter + id: required_confirmation_count + stepSize: 1 + from: 1 + to: 5 + live: true + snapMode: Slider.SnapAlways + value: default_confirmation_count + } } } // Warning when both are off DefaultText { - visible: !enable_dpow_confs.checked && !enable_normal_confs.checked + visible: enable_custom_config.visible && enable_custom_config.enabled && enable_custom_config.checked && + !enable_dpow_confs.checked Layout.alignment: Qt.AlignHCenter - text_value: API.get().empty_string + (qsTr("Warning, this atomic swap is not dPoW/blockchain confirmation protected")) + text_value: API.get().empty_string + (qsTr("Warning, this atomic swap is not dPoW protected")) color: Style.colorRed } } @@ -172,12 +181,9 @@ DefaultModal { root.close() trade(getTicker(true), getTicker(false), { - enable_dpow_confs: enable_dpow_confs.enabled && enable_dpow_confs.checked, - dpow_configuration: { - enable_notarization: enable_notarization.checked - }, - - enable_normal_confs: enable_normal_confs.enabled && enable_normal_confs.checked, + enable_custom_config: enable_custom_config.visible && enable_custom_config.enabled && enable_custom_config.checked, + enable_dpow_confs: enable_dpow_confs.visible && enable_dpow_confs.enabled && enable_dpow_confs.checked, + enable_normal_confs: enable_normal_confs.visible && enable_normal_confs.enabled && enable_normal_confs.checked, normal_configuration: { required_confirmation_count: required_confirmation_count.value }, diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index c25de8b1eb..e938dbe68a 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -273,15 +273,16 @@ Item { updateTradeInfo(true) // Force update trade info and cap the value for one last time let nota = "" - if(options.enable_dpow_confs) { - nota = options.dpow_configuration.enable_notarization ? "1" : "0" - } - let confs = "" - if(options.enable_normal_confs) { - confs = options.normal_configuration.required_confirmation_count.toString() + if(options.enable_custom_config) { + nota = options.enable_dpow_confs ? "1" : "0" + + if(!options.enable_dpow_confs && options.enable_normal_confs) { + confs = options.normal_configuration.required_confirmation_count.toString() + } } + const current_form = getCurrentForm() const is_created_order = !orderIsSelected() From 89667f00a5dc96972b55cf30ad12db1c783cb228 Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 5 Aug 2020 18:23:20 +0300 Subject: [PATCH 180/515] feat(gui): warning texts and info link --- .../qml/Exchange/Trade/ConfirmTradeModal.qml | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml index 18084b82e4..426b4e0485 100644 --- a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml +++ b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml @@ -103,7 +103,6 @@ DefaultModal { visible: enable_custom_config.checked Layout.alignment: Qt.AlignHCenter - Layout.leftMargin: 40 // dPoW configuration switch Switch { @@ -118,6 +117,16 @@ DefaultModal { text: API.get().empty_string + (qsTr("Enable Komodo dPoW security")) } + DefaultText { + Layout.alignment: Qt.AlignHCenter + text_value: API.get().empty_string + (General.cex_icon + " " + qsTr('Read more about dPoW')) + wrapMode: Text.WordWrap + font.pixelSize: Style.textSizeSmall2 + + onLinkActivated: Qt.openUrlExternally(link) + linkColor: color + } + // Normal configuration switch Switch { id: enable_normal_confs @@ -133,7 +142,6 @@ DefaultModal { ColumnLayout { Layout.alignment: Qt.AlignHCenter visible: !enable_dpow_confs.checked && enable_normal_confs.checked - Layout.leftMargin: custom_config.Layout.leftMargin DefaultText { Layout.alignment: Qt.AlignHCenter @@ -156,13 +164,27 @@ DefaultModal { } } - // Warning when both are off - DefaultText { + FloatingBackground { visible: enable_custom_config.visible && enable_custom_config.enabled && enable_custom_config.checked && !enable_dpow_confs.checked Layout.alignment: Qt.AlignHCenter - text_value: API.get().empty_string + (qsTr("Warning, this atomic swap is not dPoW protected")) - color: Style.colorRed + Layout.bottomMargin: 10 + + color: Style.colorRed3 + + width: dpow_off_warning.width + 20 + height: dpow_off_warning.height + 20 + + ColumnLayout { + id: dpow_off_warning + anchors.centerIn: parent + + DefaultText { + Layout.alignment: Qt.AlignHCenter + + text_value: API.get().empty_string + ("⚠️ " + qsTr("Warning, this atomic swap is not dPoW protected!")) + } + } } } From 9c2035df3932c6458dff6ba83a4e43da4672ce21 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Wed, 5 Aug 2020 18:11:14 +0200 Subject: [PATCH 181/515] enhancements(trading): big refactor trading backend --- CMakeLists.txt | 1 + .../qml/Exchange/Trade/CandleStickChart.qml | 6 +- .../qml/Exchange/Trade/Orderbook.qml | 4 +- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 2 +- src/atomic.dex.app.cpp | 96 ++--------- src/atomic.dex.app.hpp | 35 +--- src/atomic.dex.qt.actions.hpp | 18 +++ src/atomic.dex.qt.trading.page.cpp | 149 ++++++++++++++++++ src/atomic.dex.qt.trading.page.hpp | 106 +++++++++++++ src/atomic.dex.qt.wallet.manager.hpp | 17 +- 10 files changed, 310 insertions(+), 124 deletions(-) create mode 100644 src/atomic.dex.qt.actions.hpp create mode 100644 src/atomic.dex.qt.trading.page.cpp create mode 100644 src/atomic.dex.qt.trading.page.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index dcefdfe67a..9d359d16d2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -162,6 +162,7 @@ target_sources(atomic_qt_shared_deps INTERFACE ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.addressbook.model.cpp ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.addressbook.proxy.filter.model.cpp ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.contact.model.cpp + ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.trading.page.cpp ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.orderbook.cpp ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.orderbook.model.cpp ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.orderbook.proxy.model.cpp diff --git a/atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml b/atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml index 728dc0530c..9366da8689 100644 --- a/atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml +++ b/atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml @@ -20,8 +20,8 @@ Item { } Component.onCompleted: { - API.get().candlestick_charts_mdl.modelReset.connect(chartUpdated) - API.get().candlestick_charts_mdl.chartFullyModelReset.connect(chartFullyReset) + API.get().trading_pg.candlestick_charts_mdl.modelReset.connect(chartUpdated) + API.get().trading_pg.candlestick_charts_mdl.chartFullyModelReset.connect(chartFullyReset) } function chartFullyReset() { @@ -207,7 +207,7 @@ Item { HCandlestickModelMapper { id: cs_mapper - model: API.get().candlestick_charts_mdl + model: API.get().trading_pg.candlestick_charts_mdl timestampColumn: 0 openColumn: 1 diff --git a/atomic_qt_design/qml/Exchange/Trade/Orderbook.qml b/atomic_qt_design/qml/Exchange/Trade/Orderbook.qml index adca3f3d62..7ef96314d4 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Orderbook.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Orderbook.qml @@ -14,7 +14,7 @@ InnerBackground { anchors.top: parent.top anchors.bottom: parent.bottom anchors.right: separator.left - model: API.get().orderbook.bids.proxy_mdl + model: API.get().trading_pg.orderbook.bids.proxy_mdl } VerticalLine { @@ -31,7 +31,7 @@ InnerBackground { anchors.left: separator.right is_asks: true - model: API.get().orderbook.asks.proxy_mdl + model: API.get().trading_pg.orderbook.asks.proxy_mdl } } } diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index 47f1a6de39..253539486c 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -261,7 +261,7 @@ Item { const new_base = getTicker(true) const rel = getTicker(false) console.log("Setting current orderbook with params: ", new_base, rel) - API.get().set_current_orderbook(new_base, rel) + API.get().trading_pg.set_current_orderbook(new_base, rel) reset(true, is_base) updateTradeInfo() updateCexPrice(new_base, rel) diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index 18e1c1f0d5..6107de490d 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -200,6 +200,8 @@ namespace atomic_dex auto& mm2_s = system_manager_.create_system(); system_manager_.create_system(mm2_s, m_config); system_manager_.create_system(mm2_s); + system_manager_.create_system(system_manager_, m_event_actions.at(events_action::about_to_exit_app), this); + connect_signals(); m_event_actions[events_action::need_a_full_refresh_of_mm2] = false; @@ -230,6 +232,7 @@ namespace atomic_dex } } + system_manager_.get_system().process_action(); if (not this->m_actions_queue.empty() && not m_event_actions[events_action::about_to_exit_app]) { action last_action; @@ -248,19 +251,6 @@ namespace atomic_dex this->process_refresh_current_ticker_infos(); } break; - case action::refresh_ohlc: - if (mm2.is_mm2_running()) - { - if (m_event_actions[events_action::candlestick_need_a_reset]) - { - qobject_cast(m_manager_models.at("candlesticks"))->init_data(); - } - else - { - qobject_cast(m_manager_models.at("candlesticks"))->update_data(); - } - } - break; case action::refresh_transactions: if (mm2.is_mm2_running()) { @@ -285,23 +275,6 @@ namespace atomic_dex qobject_cast(m_manager_models.at("orders"))->refresh_or_insert_swaps(); } break; - case action::post_process_orderbook_finished: - if (mm2.is_mm2_running()) - { - std::error_code ec; - t_orderbook_answer result = get_mm2().get_orderbook(ec); - if (!ec) - { - if (m_event_actions[events_action::orderbook_need_a_reset]) - { - qobject_cast(m_manager_models.at("orderbook"))->reset_orderbook(result); - } - else - { - qobject_cast(m_manager_models.at("orderbook"))->refresh_orderbook(result); - } - } - } case action::refresh_update_status: spdlog::trace("refreshing update status in GUI"); const auto& update_service_sys = this->system_manager_.get_system(); @@ -406,8 +379,6 @@ namespace atomic_dex {"addressbook", new addressbook_model(this->m_wallet_manager, this)}, {"portfolio", new portfolio_model(this->system_manager_, this->m_config, this)}, {"orders", new orders_model(this->system_manager_, this->dispatcher_, this)}, - {"candlesticks", new candlestick_charts_model(this->system_manager_, this)}, - {"orderbook", new qt_orderbook_wrapper(this->system_manager_, this)}, {"internet_service", std::addressof(system_manager_.create_system(this))}, {"notifications", new notification_manager(this->dispatcher_, this)}} @@ -418,6 +389,7 @@ namespace atomic_dex system_manager_.create_system(mm2_system, m_config); system_manager_.create_system(mm2_system); system_manager_.create_system(); + system_manager_.create_system(system_manager_, m_event_actions.at(events_action::about_to_exit_app), this); connect_signals(); if (is_there_a_default_wallet()) @@ -783,15 +755,6 @@ namespace atomic_dex this->set_status("complete"); } - void - application::set_current_orderbook(const QString& base, const QString& rel) - { - auto& provider = this->system_manager_.get_system(); - auto [normal, quoted] = provider.is_pair_supported(base.toStdString(), rel.toStdString()); - qobject_cast(m_manager_models.at("candlesticks"))->set_is_pair_supported(normal || quoted); - this->dispatcher_.trigger(base.toStdString(), rel.toStdString()); - } - void application::on_refresh_update_status_event([[maybe_unused]] const refresh_update_status& evt) noexcept { @@ -867,8 +830,10 @@ namespace atomic_dex system_manager_.mark_system(); system_manager_.mark_system(); system_manager_.mark_system(); + system_manager_.mark_system(); //! Disconnect signals + system_manager_.get_system().disconnect_signals(); qobject_cast(m_manager_models.at("notifications"))->disconnect_signals(); get_dispatcher().sink().disconnect<&application::on_ticker_balance_updated_event>(*this); get_dispatcher().sink().disconnect<&application::on_change_ticker_event>(*this); @@ -879,11 +844,8 @@ namespace atomic_dex get_dispatcher().sink().disconnect<&application::on_coin_disabled_event>(*this); get_dispatcher().sink().disconnect<&application::on_mm2_initialized_event>(*this); get_dispatcher().sink().disconnect<&application::on_mm2_started_event>(*this); - get_dispatcher().sink().disconnect<&application::on_refresh_ohlc_event>(*this); get_dispatcher().sink().disconnect<&application::on_process_orders_finished_event>(*this); get_dispatcher().sink().disconnect<&application::on_process_swaps_finished_event>(*this); - get_dispatcher().sink().disconnect<&application::on_process_orderbook_finished_event>(*this); - get_dispatcher().sink().disconnect<&application::on_start_fetching_new_ohlc_data_event>(*this); m_event_actions[events_action::need_a_full_refresh_of_mm2] = true; @@ -897,6 +859,7 @@ namespace atomic_dex { spdlog::debug("{} l{}", __FUNCTION__, __LINE__); qobject_cast(m_manager_models.at("notifications"))->connect_signals(); + system_manager_.get_system().connect_signals(); get_dispatcher().sink().connect<&application::on_ticker_balance_updated_event>(*this); get_dispatcher().sink().connect<&application::on_change_ticker_event>(*this); get_dispatcher().sink().connect<&application::on_enabled_coins_event>(*this); @@ -906,11 +869,8 @@ namespace atomic_dex get_dispatcher().sink().connect<&application::on_coin_disabled_event>(*this); get_dispatcher().sink().connect<&application::on_mm2_initialized_event>(*this); get_dispatcher().sink().connect<&application::on_mm2_started_event>(*this); - get_dispatcher().sink().connect<&application::on_refresh_ohlc_event>(*this); get_dispatcher().sink().connect<&application::on_process_orders_finished_event>(*this); get_dispatcher().sink().connect<&application::on_process_swaps_finished_event>(*this); - get_dispatcher().sink().connect<&application::on_process_orderbook_finished_event>(*this); - get_dispatcher().sink().connect<&application::on_start_fetching_new_ohlc_data_event>(*this); } QString @@ -1264,12 +1224,6 @@ namespace atomic_dex //! OHLC Relative functions namespace atomic_dex { - candlestick_charts_model* - application::get_candlestick_charts() const noexcept - { - return qobject_cast(m_manager_models.at("candlesticks")); - } - QVariantMap application::find_closest_ohlc_data(int range, int timestamp) { @@ -1290,17 +1244,6 @@ namespace atomic_dex return out; } - void - application::on_refresh_ohlc_event([[maybe_unused]] const refresh_ohlc_needed& evt) noexcept - { - spdlog::debug("{} l{}", __FUNCTION__, __LINE__); - if (not m_event_actions[events_action::about_to_exit_app]) - { - this->m_actions_queue.push(action::refresh_ohlc); - m_event_actions[events_action::candlestick_need_a_reset] = evt.is_a_reset; - } - } - void application::on_ticker_balance_updated_event(const ticker_balance_updated& evt) noexcept { @@ -1493,30 +1436,17 @@ namespace atomic_dex m_event_actions[events_action::about_to_exit_app] = true; } - void - application::on_start_fetching_new_ohlc_data_event(const start_fetching_new_ohlc_data& evt) - { - qobject_cast(m_manager_models.at("candlesticks"))->set_is_currently_fetching(evt.is_a_reset); - } } // namespace atomic_dex -//! Orderbook +//! trading namespace atomic_dex { - qt_orderbook_wrapper* - application::get_orderbook_wrapper() const noexcept - { - return qobject_cast(m_manager_models.at("orderbook")); - } - - void - application::on_process_orderbook_finished_event(const process_orderbook_finished& evt) noexcept + trading_page* + application::get_trading_page() const noexcept { - if (not m_event_actions[events_action::about_to_exit_app]) - { - this->m_actions_queue.push(action::post_process_orderbook_finished); - m_event_actions[events_action::orderbook_need_a_reset] = evt.is_a_reset; - } + trading_page* ptr = const_cast(std::addressof(system_manager_.get_system())); + assert(ptr != nullptr); + return ptr; } } // namespace atomic_dex diff --git a/src/atomic.dex.app.hpp b/src/atomic.dex.app.hpp index cc0b224fa9..178748a2df 100644 --- a/src/atomic.dex.app.hpp +++ b/src/atomic.dex.app.hpp @@ -43,11 +43,11 @@ #include "atomic.dex.qt.orders.model.hpp" #include "atomic.dex.qt.portfolio.model.hpp" #include "atomic.dex.qt.wallet.manager.hpp" +#include "atomic.dex.qt.actions.hpp" +#include "atomic.dex.qt.trading.page.hpp" namespace ag = antara::gaming; -inline constexpr std::size_t g_max_actions_size{128}; - namespace atomic_dex { struct application : public QObject, public ag::world::app @@ -61,12 +61,11 @@ namespace atomic_dex Q_PROPERTY(QObject* current_coin_info READ get_current_coin_info NOTIFY coinInfoChanged) Q_PROPERTY(addressbook_model* addressbook_mdl READ get_addressbook NOTIFY addressbookChanged) Q_PROPERTY(orders_model* orders_mdl READ get_orders NOTIFY ordersChanged) - Q_PROPERTY(qt_orderbook_wrapper* orderbook READ get_orderbook_wrapper NOTIFY orderbookChanged) - Q_PROPERTY(candlestick_charts_model* candlestick_charts_mdl READ get_candlestick_charts NOTIFY candlestickChartsChanged) Q_PROPERTY(QVariant update_status READ get_update_status NOTIFY updateStatusChanged) Q_PROPERTY(portfolio_model* portfolio_mdl READ get_portfolio NOTIFY portfolioChanged) Q_PROPERTY(notification_manager* notification_mgr READ get_notification_manager) Q_PROPERTY(internet_service_checker* internet_checker READ get_internet_checker NOTIFY internetCheckerChanged) + Q_PROPERTY(trading_page* trading_pg READ get_trading_page NOTIFY tradingPageChanged) Q_PROPERTY(QString current_currency READ get_current_currency WRITE set_current_currency NOTIFY onCurrencyChanged) Q_PROPERTY(QString current_currency_sign READ get_current_currency_sign NOTIFY onCurrencySignChanged) Q_PROPERTY(QString current_fiat_sign READ get_current_fiat_sign NOTIFY onFiatSignChanged) @@ -85,20 +84,6 @@ namespace atomic_dex void process_refresh_enabled_coin_action(); void process_refresh_current_ticker_infos(); - //! Private enums - enum class action - { - refresh_enabled_coin = 0, - refresh_current_ticker = 1, - refresh_ohlc = 2, - refresh_transactions = 3, - refresh_portfolio_ticker_balance = 4, - refresh_update_status = 5, - post_process_orders_finished = 6, - post_process_swaps_finished = 7, - post_process_orderbook_finished = 8 - }; - enum events_action { need_a_full_refresh_of_mm2 = 0, @@ -146,12 +131,9 @@ namespace atomic_dex void on_coin_disabled_event(const coin_disabled&) noexcept; void on_mm2_initialized_event(const mm2_initialized&) noexcept; void on_mm2_started_event(const mm2_started&) noexcept; - void on_refresh_ohlc_event(const refresh_ohlc_needed&) noexcept; void on_refresh_update_status_event(const refresh_update_status&) noexcept; void on_process_orders_finished_event(const process_orders_finished&) noexcept; void on_process_swaps_finished_event(const process_swaps_finished&) noexcept; - void on_process_orderbook_finished_event(const process_orderbook_finished&) noexcept; - void on_start_fetching_new_ohlc_data_event(const start_fetching_new_ohlc_data&); //! Properties Getter static const QString& get_empty_string(); @@ -164,9 +146,8 @@ namespace atomic_dex portfolio_model* get_portfolio() const noexcept; orders_model* get_orders() const noexcept; notification_manager* get_notification_manager() const noexcept; - candlestick_charts_model* get_candlestick_charts() const noexcept; + trading_page* get_trading_page() const noexcept; internet_service_checker* get_internet_checker() const noexcept; - qt_orderbook_wrapper* get_orderbook_wrapper() const noexcept; QVariantList get_enabled_coins() const noexcept; QVariantList get_enableable_coins() const noexcept; QString get_current_currency() const noexcept; @@ -247,7 +228,6 @@ namespace atomic_dex Q_INVOKABLE QString place_sell_order( const QString& base, const QString& rel, const QString& price, const QString& volume, bool is_created_order, const QString& price_denom, const QString& price_numer); - Q_INVOKABLE void set_current_orderbook(const QString& base, const QString& rel); Q_INVOKABLE bool do_i_have_enough_funds(const QString& ticker, const QString& amount) const; Q_INVOKABLE bool disable_coins(const QStringList& coins); Q_INVOKABLE bool is_claiming_ready(const QString& ticker); @@ -281,12 +261,13 @@ namespace atomic_dex void onWalletDefaultNameChanged(); void myOrdersUpdated(); void addressbookChanged(); - void OHLCDataUpdated(); + //void OHLCDataUpdated(); void portfolioChanged(); void updateStatusChanged(); void ordersChanged(); - void candlestickChartsChanged(); - void orderbookChanged(); + //void candlestickChartsChanged(); + //void orderbookChanged(); + void tradingPageChanged(); void internetCheckerChanged(); public slots: void exit_handler(); diff --git a/src/atomic.dex.qt.actions.hpp b/src/atomic.dex.qt.actions.hpp new file mode 100644 index 0000000000..c719956fb9 --- /dev/null +++ b/src/atomic.dex.qt.actions.hpp @@ -0,0 +1,18 @@ +#pragma once + +namespace atomic_dex +{ + //! Possible front end actions + enum class action + { + refresh_enabled_coin = 0, + refresh_current_ticker = 1, + refresh_transactions = 2, + refresh_portfolio_ticker_balance = 3, + refresh_update_status = 4, + post_process_orders_finished = 5, + post_process_swaps_finished = 6, + }; + + inline constexpr std::size_t g_max_actions_size{128}; +} // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.trading.page.cpp b/src/atomic.dex.qt.trading.page.cpp new file mode 100644 index 0000000000..cf9c4ef73c --- /dev/null +++ b/src/atomic.dex.qt.trading.page.cpp @@ -0,0 +1,149 @@ +/****************************************************************************** + * Copyright © 2013-2019 The Komodo Platform Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * Komodo Platform software, including this file may be copied, modified, * + * propagated or distributed except according to the terms contained in the * + * LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + +//! Project Headers +#include "atomic.dex.qt.trading.page.hpp" +#include "atomic.dex.mm2.hpp" +#include "atomic.dex.provider.cex.prices.hpp" + +//! Consttructor / Destructor +namespace atomic_dex +{ + trading_page::trading_page(entt::registry& registry, ag::ecs::system_manager& system_manager, std::atomic_bool& exit_status, QObject* parent) : + QObject(parent), system(registry), m_system_manager(system_manager), + m_about_to_exit_the_app(exit_status), m_models{{new qt_orderbook_wrapper(m_system_manager, this), new candlestick_charts_model(m_system_manager, this)}} + { + //! + } +} // namespace atomic_dex + +//! Events callback +namespace atomic_dex +{ + void + trading_page::on_process_orderbook_finished_event(const atomic_dex::process_orderbook_finished& evt) noexcept + { + if (not m_about_to_exit_the_app) + { + m_actions_queue.push(trading_actions::post_process_orderbook_finished); + m_models_actions[orderbook_need_a_reset] = evt.is_a_reset; + } + } + + void + trading_page::on_start_fetching_new_ohlc_data_event(const start_fetching_new_ohlc_data& evt) + { + get_candlestick_charts()->set_is_currently_fetching(evt.is_a_reset); + } + + void + atomic_dex::trading_page::on_refresh_ohlc_event(const atomic_dex::refresh_ohlc_needed& evt) noexcept + { + if (not m_about_to_exit_the_app) + { + m_actions_queue.push(trading_actions::refresh_ohlc); + m_models_actions[candlestick_need_a_reset] = evt.is_a_reset; + } + } +} // namespace atomic_dex + +//! Public QML API +namespace atomic_dex +{ + void + atomic_dex::trading_page::set_current_orderbook(const QString& base, const QString& rel) + { + auto& provider = m_system_manager.get_system(); + auto [normal, quoted] = provider.is_pair_supported(base.toStdString(), rel.toStdString()); + get_candlestick_charts()->set_is_pair_supported(normal || quoted); + dispatcher_.trigger(base.toStdString(), rel.toStdString()); + } +} // namespace atomic_dex + +//! Public API +namespace atomic_dex +{ + void + trading_page::update() noexcept + { + } + + void + trading_page::connect_signals() + { + dispatcher_.sink().connect<&trading_page::on_process_orderbook_finished_event>(*this); + dispatcher_.sink().connect<&trading_page::on_start_fetching_new_ohlc_data_event>(*this); + dispatcher_.sink().connect<&trading_page::on_refresh_ohlc_event>(*this); + } + + void + atomic_dex::trading_page::disconnect_signals() + { + dispatcher_.sink().disconnect<&trading_page::on_process_orderbook_finished_event>(*this); + dispatcher_.sink().disconnect<&trading_page::on_start_fetching_new_ohlc_data_event>(*this); + dispatcher_.sink().disconnect<&trading_page::on_refresh_ohlc_event>(*this); + } + + void + trading_page::process_action() + { + if (m_actions_queue.empty() || m_about_to_exit_the_app) + { + return; + } + const auto& mm2_system = m_system_manager.get_system(); + trading_actions last_action; + this->m_actions_queue.pop(last_action); + if (mm2_system.is_mm2_running()) + { + switch (last_action) + { + case trading_actions::refresh_ohlc: + m_models_actions[candlestick_need_a_reset] ? get_candlestick_charts()->init_data() : get_candlestick_charts()->update_data(); + break; + case trading_actions::post_process_orderbook_finished: + { + std::error_code ec; + t_orderbook_answer result = mm2_system.get_orderbook(ec); + if (!ec) + { + auto* wrapper = get_orderbook_wrapper(); + m_models_actions[orderbook_need_a_reset] ? wrapper->reset_orderbook(result) : wrapper->refresh_orderbook(result); + } + break; + } + default: + break; + } + } + } +} // namespace atomic_dex + +//! Properties +namespace atomic_dex +{ + qt_orderbook_wrapper* + trading_page::get_orderbook_wrapper() const noexcept + { + return qobject_cast(m_models[models::orderbook]); + } + + candlestick_charts_model* + trading_page::get_candlestick_charts() const noexcept + { + return qobject_cast(m_models[models::ohlc]); + } +} // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.trading.page.hpp b/src/atomic.dex.qt.trading.page.hpp new file mode 100644 index 0000000000..f56ebf2864 --- /dev/null +++ b/src/atomic.dex.qt.trading.page.hpp @@ -0,0 +1,106 @@ +/****************************************************************************** + * Copyright © 2013-2019 The Komodo Platform Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * Komodo Platform software, including this file may be copied, modified, * + * propagated or distributed except according to the terms contained in the * + * LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + +#pragma once + +//! QT +#include + +//! PCH +#include "atomic.dex.pch.hpp" + +//! Project Headers +#include "atomic.dex.events.hpp" +#include "atomic.dex.qt.actions.hpp" +#include "atomic.dex.qt.candlestick.charts.model.hpp" +#include "atomic.dex.qt.orderbook.hpp" + +namespace atomic_dex +{ + class trading_page final : public QObject, public ag::ecs::pre_update_system + { + //! Q_Object definition + Q_OBJECT + + //! Q Properties definitions + Q_PROPERTY(qt_orderbook_wrapper* orderbook READ get_orderbook_wrapper NOTIFY orderbookChanged) + Q_PROPERTY(candlestick_charts_model* candlestick_charts_mdl READ get_candlestick_charts NOTIFY candlestickChartsChanged) + + //! Private enum + enum models + { + orderbook = 0, + ohlc = 1, + models_size = 2 + }; + + enum models_actions + { + candlestick_need_a_reset = 0, + orderbook_need_a_reset = 1, + models_actions_size = 2 + }; + + enum class trading_actions + { + post_process_orderbook_finished = 0, + refresh_ohlc = 1, + }; + + //! Private typedefs + using t_models = std::array; + using t_models_actions = std::array; + using t_actions_queue = boost::lockfree::queue; + + //! Private members fields + ag::ecs::system_manager& m_system_manager; + std::atomic_bool& m_about_to_exit_the_app; + t_models m_models; + t_models_actions m_models_actions; + t_actions_queue m_actions_queue{g_max_actions_size}; + + public: + //! Constructor + explicit trading_page(entt::registry& registry, ag::ecs::system_manager& system_manager, std::atomic_bool& exit_status, QObject* parent = nullptr); + ~trading_page() noexcept final = default; + + //! Public override + void update() noexcept final; + + //! Public API + void process_action(); + void connect_signals(); + void disconnect_signals(); + + //! Public QML API + Q_INVOKABLE void set_current_orderbook(const QString& base, const QString& rel); + + //! Properties + [[nodiscard]] qt_orderbook_wrapper* get_orderbook_wrapper() const noexcept; + [[nodiscard]] candlestick_charts_model* get_candlestick_charts() const noexcept; + + //! Events Callbacks + void on_process_orderbook_finished_event(const process_orderbook_finished& evt) noexcept; + void on_start_fetching_new_ohlc_data_event(const start_fetching_new_ohlc_data& evt); + void on_refresh_ohlc_event(const refresh_ohlc_needed& evt) noexcept; + + signals: + void orderbookChanged(); + void candlestickChartsChanged(); + }; +} // namespace atomic_dex + +REFL_AUTO(type(atomic_dex::trading_page)) \ No newline at end of file diff --git a/src/atomic.dex.qt.wallet.manager.hpp b/src/atomic.dex.qt.wallet.manager.hpp index 3e1c580f7d..10f7e745b3 100644 --- a/src/atomic.dex.qt.wallet.manager.hpp +++ b/src/atomic.dex.qt.wallet.manager.hpp @@ -35,7 +35,7 @@ namespace atomic_dex { public: QString get_wallet_default_name() const noexcept; - void just_set_wallet_name(QString wallet_name); + void just_set_wallet_name(QString wallet_name); void set_wallet_default_name(QString wallet_name) noexcept; @@ -58,13 +58,14 @@ namespace atomic_dex bool update_wallet_cfg() noexcept; - void update_contact_ticker(const QString& contact_name, const QString& old_ticker, const QString& new_ticker); - void update_contact_address(const QString& contact_name, const QString& ticker, const QString& address); - void update_or_insert_contact_name(const QString& old_contact_name, const QString& contact_name); - void remove_address_entry(const QString& contact_name, const QString& ticker); - void delete_contact(const QString& contact_name); - const wallet_cfg& get_wallet_cfg() const noexcept; - const wallet_cfg& get_wallet_cfg() noexcept; + void update_contact_ticker(const QString& contact_name, const QString& old_ticker, const QString& new_ticker); + void update_contact_address(const QString& contact_name, const QString& ticker, const QString& address); + void update_or_insert_contact_name(const QString& old_contact_name, const QString& contact_name); + void remove_address_entry(const QString& contact_name, const QString& ticker); + void delete_contact(const QString& contact_name); + [[nodiscard]] const wallet_cfg& get_wallet_cfg() const noexcept; + const wallet_cfg& get_wallet_cfg() noexcept; + private: wallet_cfg m_wallet_cfg; QString m_current_default_wallet{""}; From b860e364ac4ff92547d22cd014ffb0b9279cde09 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Wed, 5 Aug 2020 20:19:38 +0200 Subject: [PATCH 182/515] enhancements(code): trading modal --- atomic_qt_design/qml/Exchange/Exchange.qml | 4 +- .../qml/Exchange/History/SwapList.qml | 2 +- .../qml/Exchange/Orders/Orders.qml | 6 +-- atomic_qt_design/qml/Screens/Dashboard.qml | 4 +- src/atomic.dex.app.cpp | 12 ++--- src/atomic.dex.app.hpp | 10 ---- src/atomic.dex.qt.trading.page.cpp | 49 ++++++++++++++++++- src/atomic.dex.qt.trading.page.hpp | 5 ++ 8 files changed, 67 insertions(+), 25 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Exchange.qml b/atomic_qt_design/qml/Exchange/Exchange.qml index 90cad0762f..fd7bbbbca4 100644 --- a/atomic_qt_design/qml/Exchange/Exchange.qml +++ b/atomic_qt_design/qml/Exchange/Exchange.qml @@ -40,11 +40,11 @@ Item { if(prev_page !== current_page) { // Handle DEX enter/exit if(current_page === General.idx_exchange_trade) { - API.get().on_gui_enter_dex() + API.get().trading_pg.on_gui_enter_dex() exchange_trade.onOpened() } else if(prev_page === General.idx_exchange_trade) { - API.get().on_gui_leave_dex() + API.get().trading_pg.on_gui_leave_dex() } // Opening of other pages diff --git a/atomic_qt_design/qml/Exchange/History/SwapList.qml b/atomic_qt_design/qml/Exchange/History/SwapList.qml index 319cdd160b..c10808df8a 100644 --- a/atomic_qt_design/qml/Exchange/History/SwapList.qml +++ b/atomic_qt_design/qml/Exchange/History/SwapList.qml @@ -15,7 +15,7 @@ InnerBackground { // Local function onCancelOrder(order_id) { - API.get().cancel_order(order_id) + API.get().trading_pg.cancel_order(order_id) postCancelOrder() } diff --git a/atomic_qt_design/qml/Exchange/Orders/Orders.qml b/atomic_qt_design/qml/Exchange/Orders/Orders.qml index ba2524970c..fafae40a58 100644 --- a/atomic_qt_design/qml/Exchange/Orders/Orders.qml +++ b/atomic_qt_design/qml/Exchange/Orders/Orders.qml @@ -14,7 +14,7 @@ Item { // Local function onCancelOrder(order_id) { - API.get().cancel_order(order_id) + API.get().trading_pg.cancel_order(order_id) } @@ -121,8 +121,8 @@ Item { text: API.get().empty_string + (show_all_coins.checked ? qsTr("Cancel All Orders") : qsTr("Cancel All %1 Orders", "TICKER").arg(base)) enabled: orders_model.length > 0 onClicked: { - if(show_all_coins.checked) API.get().cancel_all_orders() - else API.get().cancel_all_orders_by_ticker(base) + if(show_all_coins.checked) API.get().trading_pg.cancel_all_orders() + else API.get().trading_pg.cancel_all_orders_by_ticker(base) } Layout.rightMargin: 15 } diff --git a/atomic_qt_design/qml/Screens/Dashboard.qml b/atomic_qt_design/qml/Screens/Dashboard.qml index 3d778dd182..0fb837d59f 100644 --- a/atomic_qt_design/qml/Screens/Dashboard.qml +++ b/atomic_qt_design/qml/Screens/Dashboard.qml @@ -52,11 +52,11 @@ Item { if(prev_page !== current_page) { // Handle DEX enter/exit if(current_page === General.idx_dashboard_exchange) { - API.get().on_gui_enter_dex() + API.get().trading_pg.on_gui_enter_dex() exchange.onOpened() } else if(prev_page === General.idx_dashboard_exchange) { - API.get().on_gui_leave_dex() + API.get().trading_pg.on_gui_leave_dex() } // Opening of other pages diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index 6107de490d..399a12c133 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -398,7 +398,7 @@ namespace atomic_dex } } - void + /*void atomic_dex::application::cancel_order(const QString& order_id) { auto& mm2 = get_mm2(); @@ -430,7 +430,7 @@ namespace atomic_dex ::mm2::api::rpc_cancel_all_orders(std::move(req)); mm2.process_orders(); }); - } + }*/ void atomic_dex::application::on_enabled_coins_event([[maybe_unused]] const enabled_coins_event& evt) noexcept @@ -716,17 +716,17 @@ namespace atomic_dex return QString::fromStdString(res); } - void + /*void application::on_gui_enter_dex() { this->dispatcher_.trigger(); - } + }*/ - void + /*void application::on_gui_leave_dex() { this->dispatcher_.trigger(); - } + }*/ QString application::get_status() const noexcept diff --git a/src/atomic.dex.app.hpp b/src/atomic.dex.app.hpp index 178748a2df..e822671cd7 100644 --- a/src/atomic.dex.app.hpp +++ b/src/atomic.dex.app.hpp @@ -204,13 +204,6 @@ namespace atomic_dex Q_INVOKABLE QString send(const QString& tx_hex); Q_INVOKABLE QString send_rewards(const QString& tx_hex); - //! Trading QML API Bindings - Q_INVOKABLE void on_gui_enter_dex(); - Q_INVOKABLE void on_gui_leave_dex(); - Q_INVOKABLE void cancel_order(const QString& order_id); - Q_INVOKABLE void cancel_all_orders(); - Q_INVOKABLE void cancel_all_orders_by_ticker(const QString& ticker); - //! Others Q_INVOKABLE static bool mnemonic_validate(const QString& entropy); Q_INVOKABLE static QString retrieve_seed(const QString& wallet_name, const QString& password); @@ -261,12 +254,9 @@ namespace atomic_dex void onWalletDefaultNameChanged(); void myOrdersUpdated(); void addressbookChanged(); - //void OHLCDataUpdated(); void portfolioChanged(); void updateStatusChanged(); void ordersChanged(); - //void candlestickChartsChanged(); - //void orderbookChanged(); void tradingPageChanged(); void internetCheckerChanged(); public slots: diff --git a/src/atomic.dex.qt.trading.page.cpp b/src/atomic.dex.qt.trading.page.cpp index cf9c4ef73c..8aec9a3173 100644 --- a/src/atomic.dex.qt.trading.page.cpp +++ b/src/atomic.dex.qt.trading.page.cpp @@ -18,6 +18,7 @@ #include "atomic.dex.qt.trading.page.hpp" #include "atomic.dex.mm2.hpp" #include "atomic.dex.provider.cex.prices.hpp" +#include "atomic.threadpool.hpp" //! Consttructor / Destructor namespace atomic_dex @@ -64,13 +65,59 @@ namespace atomic_dex namespace atomic_dex { void - atomic_dex::trading_page::set_current_orderbook(const QString& base, const QString& rel) + trading_page::set_current_orderbook(const QString& base, const QString& rel) { auto& provider = m_system_manager.get_system(); auto [normal, quoted] = provider.is_pair_supported(base.toStdString(), rel.toStdString()); get_candlestick_charts()->set_is_pair_supported(normal || quoted); dispatcher_.trigger(base.toStdString(), rel.toStdString()); } + + void + trading_page::on_gui_enter_dex() + { + dispatcher_.trigger(); + } + + void + trading_page::on_gui_leave_dex() + { + dispatcher_.trigger(); + } + + void + trading_page::cancel_order(const QString& order_id) + { + auto& mm2_system = m_system_manager.get_system(); + spawn([&mm2_system, order_id]() { + ::mm2::api::rpc_cancel_order({order_id.toStdString()}); + mm2_system.process_orders(); + }); + } + + void + trading_page::cancel_all_orders() + { + auto& mm2_system = m_system_manager.get_system(); + atomic_dex::spawn([&mm2_system]() { + ::mm2::api::cancel_all_orders_request req; + ::mm2::api::rpc_cancel_all_orders(std::move(req)); + mm2_system.process_orders(); + }); + } + + void + trading_page::cancel_all_orders_by_ticker(const QString& ticker) + { + auto& mm2_system = m_system_manager.get_system(); + atomic_dex::spawn([&mm2_system, &ticker]() { + ::mm2::api::cancel_data cd; + cd.ticker = ticker.toStdString(); + ::mm2::api::cancel_all_orders_request req{{"Coin", cd}}; + ::mm2::api::rpc_cancel_all_orders(std::move(req)); + mm2_system.process_orders(); + }); + } } // namespace atomic_dex //! Public API diff --git a/src/atomic.dex.qt.trading.page.hpp b/src/atomic.dex.qt.trading.page.hpp index f56ebf2864..f2a6e05951 100644 --- a/src/atomic.dex.qt.trading.page.hpp +++ b/src/atomic.dex.qt.trading.page.hpp @@ -87,6 +87,11 @@ namespace atomic_dex //! Public QML API Q_INVOKABLE void set_current_orderbook(const QString& base, const QString& rel); + Q_INVOKABLE void on_gui_enter_dex(); + Q_INVOKABLE void on_gui_leave_dex(); + Q_INVOKABLE void cancel_order(const QString& order_id); + Q_INVOKABLE void cancel_all_orders(); + Q_INVOKABLE void cancel_all_orders_by_ticker(const QString& ticker); //! Properties [[nodiscard]] qt_orderbook_wrapper* get_orderbook_wrapper() const noexcept; From 06366097498f7ae43f996c4dab2cf4eac40157bc Mon Sep 17 00:00:00 2001 From: romanszterg Date: Wed, 5 Aug 2020 20:22:02 +0200 Subject: [PATCH 183/515] enhancements(code): clean transition --- src/atomic.dex.app.cpp | 46 ------------------------------------------ 1 file changed, 46 deletions(-) diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index 399a12c133..70731e54b1 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -398,40 +398,6 @@ namespace atomic_dex } } - /*void - atomic_dex::application::cancel_order(const QString& order_id) - { - auto& mm2 = get_mm2(); - atomic_dex::spawn([&mm2, order_id]() { - ::mm2::api::rpc_cancel_order({order_id.toStdString()}); - mm2.process_orders(); - }); - } - - void - atomic_dex::application::cancel_all_orders() - { - auto& mm2 = get_mm2(); - atomic_dex::spawn([&mm2]() { - ::mm2::api::cancel_all_orders_request req; - ::mm2::api::rpc_cancel_all_orders(std::move(req)); - mm2.process_orders(); - }); - } - - void - application::cancel_all_orders_by_ticker(const QString& ticker) - { - auto& mm2 = get_mm2(); - atomic_dex::spawn([&mm2, &ticker]() { - ::mm2::api::cancel_data cd; - cd.ticker = ticker.toStdString(); - ::mm2::api::cancel_all_orders_request req{{"Coin", cd}}; - ::mm2::api::rpc_cancel_all_orders(std::move(req)); - mm2.process_orders(); - }); - }*/ - void atomic_dex::application::on_enabled_coins_event([[maybe_unused]] const enabled_coins_event& evt) noexcept { @@ -716,18 +682,6 @@ namespace atomic_dex return QString::fromStdString(res); } - /*void - application::on_gui_enter_dex() - { - this->dispatcher_.trigger(); - }*/ - - /*void - application::on_gui_leave_dex() - { - this->dispatcher_.trigger(); - }*/ - QString application::get_status() const noexcept { From a1f32b8e5c3e319d38211c873a9f157e3b6c2cc4 Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 5 Aug 2020 23:16:36 +0300 Subject: [PATCH 184/515] feat(gui): disable configuration for non-smartchain coins --- .../qml/Exchange/Trade/ConfirmTradeModal.qml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml index 426b4e0485..d4a42d07c5 100644 --- a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml +++ b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml @@ -86,14 +86,21 @@ DefaultModal { } ColumnLayout { + id: config_section + + readonly property bool is_configurable: API.get().get_coin_info(getTicker(!sell_mode)).type === "Smart Chain" + + visible: is_configurable + Layout.bottomMargin: 10 Layout.alignment: Qt.AlignHCenter - // Enable custom config DefaultCheckBox { Layout.alignment: Qt.AlignHCenter id: enable_custom_config + + enabled: parent.visible text: API.get().empty_string + (qsTr("Use custom protection settings")) } @@ -203,7 +210,7 @@ DefaultModal { root.close() trade(getTicker(true), getTicker(false), { - enable_custom_config: enable_custom_config.visible && enable_custom_config.enabled && enable_custom_config.checked, + enable_custom_config: config_section.is_configurable && enable_custom_config.visible && enable_custom_config.enabled && enable_custom_config.checked, enable_dpow_confs: enable_dpow_confs.visible && enable_dpow_confs.enabled && enable_dpow_confs.checked, enable_normal_confs: enable_normal_confs.visible && enable_normal_confs.enabled && enable_normal_confs.checked, normal_configuration: { From 8efe075b367bf3fcd171401691130b115cd4a7a5 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Thu, 6 Aug 2020 08:02:42 +0200 Subject: [PATCH 185/515] enhancements(code): trading page --- .../qml/Exchange/Trade/CandleStickChart.qml | 2 +- src/atomic.dex.app.cpp | 22 +----------- src/atomic.dex.app.hpp | 1 - ...atomic.dex.qt.candlestick.charts.model.cpp | 34 +++++++++++++------ ...atomic.dex.qt.candlestick.charts.model.hpp | 3 ++ 5 files changed, 28 insertions(+), 34 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml b/atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml index 9366da8689..b8951d6b99 100644 --- a/atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml +++ b/atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml @@ -598,7 +598,7 @@ Item { const cp = chart.mapToValue(Qt.point(mouse_x, mouse_y), series) // Find closest real data - const realData = API.get().find_closest_ohlc_data(getChartSeconds(), cp.x / 1000) + const realData = API.get().trading_pg.candlestick_charts_mdl.find_closest_ohlc_data(cp.x / 1000) const realDataFound = realData.timestamp if(realDataFound) { cursor_vertical_line.x = chart.mapToPosition(Qt.point(realData.timestamp*1000, 0), series).x diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index 70731e54b1..cadb733b65 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -1175,29 +1175,9 @@ namespace atomic_dex } } // namespace atomic_dex -//! OHLC Relative functions +//! Ticker balance change namespace atomic_dex { - QVariantMap - application::find_closest_ohlc_data(int range, int timestamp) - { - QVariantMap out; - auto& provider = this->system_manager_.get_system(); - auto json = provider.get_ohlc_data(std::to_string(range)); - - auto it = std::lower_bound(rbegin(json), rend(json), timestamp, [](const nlohmann::json& current_json, int timestamp) { - int res = current_json.at("timestamp").get(); - return timestamp < res; - }); - - if (it != json.rend()) - { - QJsonDocument q_json = QJsonDocument::fromJson(QString::fromStdString(it->dump()).toUtf8()); - out = q_json.object().toVariantMap(); - } - return out; - } - void application::on_ticker_balance_updated_event(const ticker_balance_updated& evt) noexcept { diff --git a/src/atomic.dex.app.hpp b/src/atomic.dex.app.hpp index e822671cd7..b8ed950658 100644 --- a/src/atomic.dex.app.hpp +++ b/src/atomic.dex.app.hpp @@ -229,7 +229,6 @@ namespace atomic_dex Q_INVOKABLE QString get_cex_rates(const QString& base, const QString& rel); Q_INVOKABLE QString get_fiat_from_amount(const QString& ticker, const QString& amount); - Q_INVOKABLE QVariantMap find_closest_ohlc_data(int range, int timestamp); Q_INVOKABLE QVariant get_coin_info(const QString& ticker); Q_INVOKABLE bool export_swaps(const QString& csv_filename) noexcept; Q_INVOKABLE bool export_swaps_json() noexcept; diff --git a/src/atomic.dex.qt.candlestick.charts.model.cpp b/src/atomic.dex.qt.candlestick.charts.model.cpp index 7d61b111fc..f132f717bd 100644 --- a/src/atomic.dex.qt.candlestick.charts.model.cpp +++ b/src/atomic.dex.qt.candlestick.charts.model.cpp @@ -14,8 +14,12 @@ * * ******************************************************************************/ +//! QT +#include +#include -#include +//! PCH +#include "atomic.dex.pch.hpp" //! Project Headers #include "atomic.dex.provider.cex.prices.hpp" @@ -176,16 +180,6 @@ namespace atomic_dex void candlestick_charts_model::update_data() { - /*auto& provider = this->m_system_manager.get_system(); - nlohmann::json ohlc_data = provider.get_ohlc_data(m_current_range); - if (ohlc_data.back().at("timestamp").get() != m_model_data.back().at("timestamp").get()) - { - this->beginInsertRows(QModelIndex(), this->m_model_data.size(), this->m_model_data.size()); - m_model_data.push_back(ohlc_data.back()); - this->endInsertRows(); - emit seriesSizeChanged(get_series_size()); - }*/ - if (not common_reset_data()) { return; @@ -483,4 +477,22 @@ namespace atomic_dex emit fetchingStatusChanged(m_currently_fetching); } } + + QVariantMap + candlestick_charts_model::find_closest_ohlc_data(int timestamp) + { + QVariantMap out; + + auto it = std::lower_bound(rbegin(m_model_data), rend(m_model_data), timestamp, [](const nlohmann::json& current_json, int timestamp) { + int res = current_json.at("timestamp").get(); + return timestamp < res; + }); + + if (it != m_model_data.rend()) + { + QJsonDocument q_json = QJsonDocument::fromJson(QString::fromStdString(it->dump()).toUtf8()); + out = q_json.object().toVariantMap(); + } + return out; + } } // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.candlestick.charts.model.hpp b/src/atomic.dex.qt.candlestick.charts.model.hpp index ae229ada69..6dac77383b 100644 --- a/src/atomic.dex.qt.candlestick.charts.model.hpp +++ b/src/atomic.dex.qt.candlestick.charts.model.hpp @@ -54,6 +54,9 @@ namespace atomic_dex void update_data(); void clear_data(); + //! Public QML API + Q_INVOKABLE QVariantMap find_closest_ohlc_data(int timestamp); + //! Property [[nodiscard]] bool is_pair_supported() const noexcept; void set_is_pair_supported(bool is_support); From c396488d97b0ebf18ee6c38ec3055306460913ce Mon Sep 17 00:00:00 2001 From: romanszterg Date: Thu, 6 Aug 2020 09:08:51 +0200 Subject: [PATCH 186/515] enhancements(code): reorder include --- src/atomic.dex.app.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/atomic.dex.app.hpp b/src/atomic.dex.app.hpp index b8ed950658..38b1993d97 100644 --- a/src/atomic.dex.app.hpp +++ b/src/atomic.dex.app.hpp @@ -34,6 +34,7 @@ #include "atomic.dex.mm2.hpp" #include "atomic.dex.notification.manager.hpp" #include "atomic.dex.provider.coinpaprika.hpp" +#include "atomic.dex.qt.actions.hpp" #include "atomic.dex.qt.addressbook.model.hpp" #include "atomic.dex.qt.bindings.hpp" #include "atomic.dex.qt.candlestick.charts.model.hpp" @@ -42,9 +43,8 @@ #include "atomic.dex.qt.orderbook.hpp" #include "atomic.dex.qt.orders.model.hpp" #include "atomic.dex.qt.portfolio.model.hpp" -#include "atomic.dex.qt.wallet.manager.hpp" -#include "atomic.dex.qt.actions.hpp" #include "atomic.dex.qt.trading.page.hpp" +#include "atomic.dex.qt.wallet.manager.hpp" namespace ag = antara::gaming; From dec57c95ced2752e47081b8cee460f9414200865 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Thu, 6 Aug 2020 09:26:18 +0200 Subject: [PATCH 187/515] enhancements(notifications): add aditional parameters for notification swap --- src/atomic.dex.events.hpp | 7 ------ src/atomic.dex.notification.manager.cpp | 2 +- src/atomic.dex.notification.manager.hpp | 4 ++-- src/atomic.dex.qt.events.hpp | 32 +++++++++++++++++++++++++ src/atomic.dex.qt.orders.model.cpp | 25 +++++++++---------- 5 files changed, 48 insertions(+), 22 deletions(-) create mode 100644 src/atomic.dex.qt.events.hpp diff --git a/src/atomic.dex.events.hpp b/src/atomic.dex.events.hpp index cc803a6eb3..6767099c71 100644 --- a/src/atomic.dex.events.hpp +++ b/src/atomic.dex.events.hpp @@ -34,13 +34,6 @@ namespace atomic_dex using process_swaps_finished = entt::tag<"gui_process_swaps_finished"_hs>; // using process_orderbook_finished = entt::tag<"gui_process_orderbook_finished"_hs>; - struct swap_status_notification - { - std::string uuid; - std::string prev_status; - std::string new_status; - }; - struct process_orderbook_finished { bool is_a_reset; diff --git a/src/atomic.dex.notification.manager.cpp b/src/atomic.dex.notification.manager.cpp index 5577e0621e..888f7232f6 100644 --- a/src/atomic.dex.notification.manager.cpp +++ b/src/atomic.dex.notification.manager.cpp @@ -33,7 +33,7 @@ namespace atomic_dex void notification_manager::on_swap_status_notification(const atomic_dex::swap_status_notification& evt) { - emit updateSwapStatus(QString::fromStdString(evt.prev_status), QString::fromStdString(evt.new_status), QString::fromStdString(evt.uuid)); + emit updateSwapStatus(evt.prev_status, evt.new_status, evt.uuid, evt.base, evt.rel, evt.human_date); } void diff --git a/src/atomic.dex.notification.manager.hpp b/src/atomic.dex.notification.manager.hpp index ae0d73501f..1ab6f582c1 100644 --- a/src/atomic.dex.notification.manager.hpp +++ b/src/atomic.dex.notification.manager.hpp @@ -23,7 +23,7 @@ #include "atomic.dex.pch.hpp" //! Project Headers -#include "atomic.dex.events.hpp" +#include "atomic.dex.qt.events.hpp" namespace atomic_dex { @@ -42,7 +42,7 @@ namespace atomic_dex void on_swap_status_notification(const swap_status_notification& evt); signals: - void updateSwapStatus(QString old_swap_status, QString new_swap_status, QString swap_uuid); + void updateSwapStatus(QString old_swap_status, QString new_swap_status, QString swap_uuid, QString base_coin, QString rel_coin, QString human_date); private: entt::dispatcher& m_dispatcher; diff --git a/src/atomic.dex.qt.events.hpp b/src/atomic.dex.qt.events.hpp new file mode 100644 index 0000000000..c3f0ced73b --- /dev/null +++ b/src/atomic.dex.qt.events.hpp @@ -0,0 +1,32 @@ +/****************************************************************************** + * Copyright © 2013-2019 The Komodo Platform Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * Komodo Platform software, including this file may be copied, modified, * + * propagated or distributed except according to the terms contained in the * + * LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + +#pragma once + +#include + +namespace atomic_dex +{ + struct swap_status_notification + { + QString uuid; + QString prev_status; + QString new_status; + QString base; + QString rel; + QString human_date; + }; +} \ No newline at end of file diff --git a/src/atomic.dex.qt.orders.model.cpp b/src/atomic.dex.qt.orders.model.cpp index 69bbbd7743..9d614db0d2 100644 --- a/src/atomic.dex.qt.orders.model.cpp +++ b/src/atomic.dex.qt.orders.model.cpp @@ -17,6 +17,7 @@ //! Project #include "atomic.dex.qt.orders.model.hpp" #include "atomic.dex.mm2.hpp" +#include "atomic.dex.qt.events.hpp" //! Utils namespace @@ -319,7 +320,7 @@ namespace atomic_dex if (data.order_status == "matched") { using namespace std::string_literals; - this->m_dispatcher.trigger(data.order_id.toStdString(), "matching"s, "matched"s); + m_dispatcher.trigger(data.order_id, "matching", "matched", data.base_coin, data.rel_coin, data.human_date); } if (this->m_swaps_id_registry.find(contents.uuid) == m_swaps_id_registry.end()) @@ -341,15 +342,17 @@ namespace atomic_dex update_value(OrdersRoles::IsRecoverableRole, contents.funds_recoverable, idx, *this); auto&& [prev_value, new_value, is_change] = update_value(OrdersRoles::OrderStatusRole, determine_order_status_from_last_event(contents), idx, *this); - if (is_change) - { - this->m_dispatcher.trigger(contents.uuid, prev_value.toString().toStdString(), new_value.toString().toStdString()); - } update_value( OrdersRoles::UnixTimestampRole, not contents.events.empty() ? contents.events.back().at("timestamp").get() : 0, idx, *this); - update_value( + auto&& [prev_value_d, new_value_d, _] = update_value( OrdersRoles::HumanDateRole, not contents.events.empty() ? QString::fromStdString(contents.events.back().at("human_timestamp").get()) : "", idx, *this); + if (is_change) + { + const QString& base_coin = data(idx, OrdersRoles::BaseCoinRole).toString(); + const QString& rel_coin = data(idx, OrdersRoles::RelCoinRole).toString(); + m_dispatcher.trigger(QString::fromStdString(contents.uuid), prev_value.toString(), new_value.toString(), base_coin, rel_coin, new_value_d.toString()); + } update_value(OrdersRoles::MakerPaymentIdRole, determine_payment_id(contents, is_maker, false), idx, *this); update_value(OrdersRoles::TakerPaymentIdRole, determine_payment_id(contents, is_maker, true), idx, *this); auto [state, msg] = extract_error(contents); @@ -453,17 +456,15 @@ namespace atomic_dex if (not res_list.empty()) { //! And then delete it - spdlog::trace("removing order with id {} from the UI", id); + spdlog::trace("removing order with id {} from the UI", id); this->removeRow(res_list.at(0).row()); to_remove.emplace(id); } } } - //std::unordered_set out; - //std::set_difference(begin(m_orders_id_registry), end(m_orders_id_registry), begin(to_remove), end(to_remove), std::inserter(out, out.begin())); - for (auto&& cur_to_remove : to_remove) { - m_orders_id_registry.erase(cur_to_remove); - } + // std::unordered_set out; + // std::set_difference(begin(m_orders_id_registry), end(m_orders_id_registry), begin(to_remove), end(to_remove), std::inserter(out, out.begin())); + for (auto&& cur_to_remove: to_remove) { m_orders_id_registry.erase(cur_to_remove); } } } From 2872840278c0bb5dc25d0f2d5de1dadfd52bff2b Mon Sep 17 00:00:00 2001 From: naezith Date: Thu, 6 Aug 2020 10:27:41 +0300 Subject: [PATCH 188/515] feat(gui): print trade config --- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index e938dbe68a..50dbbc8588 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -274,6 +274,7 @@ Item { let nota = "" let confs = "" + console.log("Trade config: ", JSON.stringify(options)) if(options.enable_custom_config) { nota = options.enable_dpow_confs ? "1" : "0" From 1479c14af2e30dab4c923160612914326a58f8ab Mon Sep 17 00:00:00 2001 From: naezith Date: Thu, 6 Aug 2020 10:48:47 +0300 Subject: [PATCH 189/515] feat(gui): change text, fix conf values submitting wrong --- atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml index d4a42d07c5..765f16fb0e 100644 --- a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml +++ b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml @@ -101,7 +101,7 @@ DefaultModal { id: enable_custom_config enabled: parent.visible - text: API.get().empty_string + (qsTr("Use custom protection settings")) + text: API.get().empty_string + (qsTr("Use custom protection settings for incoming %1 transactions", "TICKER").arg(getTicker(!sell_mode))) } // Configuration settings @@ -207,8 +207,6 @@ DefaultModal { text: API.get().empty_string + (qsTr("Confirm")) Layout.fillWidth: true onClicked: { - root.close() - trade(getTicker(true), getTicker(false), { enable_custom_config: config_section.is_configurable && enable_custom_config.visible && enable_custom_config.enabled && enable_custom_config.checked, enable_dpow_confs: enable_dpow_confs.visible && enable_dpow_confs.enabled && enable_dpow_confs.checked, @@ -217,6 +215,8 @@ DefaultModal { required_confirmation_count: required_confirmation_count.value }, }) + + root.close() } } } From 49bf789f7be032afe80afeed2cd49c40652591dc Mon Sep 17 00:00:00 2001 From: naezith Date: Thu, 6 Aug 2020 10:54:47 +0300 Subject: [PATCH 190/515] feat(gui): better conf submission --- atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml index 765f16fb0e..a4ea4928ff 100644 --- a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml +++ b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml @@ -208,9 +208,9 @@ DefaultModal { Layout.fillWidth: true onClicked: { trade(getTicker(true), getTicker(false), { - enable_custom_config: config_section.is_configurable && enable_custom_config.visible && enable_custom_config.enabled && enable_custom_config.checked, - enable_dpow_confs: enable_dpow_confs.visible && enable_dpow_confs.enabled && enable_dpow_confs.checked, - enable_normal_confs: enable_normal_confs.visible && enable_normal_confs.enabled && enable_normal_confs.checked, + enable_custom_config: config_section.is_configurable && enable_custom_config.checked, + enable_dpow_confs: enable_dpow_confs.checked, + enable_normal_confs: enable_normal_confs.checked, normal_configuration: { required_confirmation_count: required_confirmation_count.value }, From 43ba79b2e29088b0edeca0c83c9bda0a0ac31afb Mon Sep 17 00:00:00 2001 From: naezith Date: Thu, 6 Aug 2020 13:52:03 +0300 Subject: [PATCH 191/515] feat(gui): remove recommended value --- atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml index a4ea4928ff..a6f0d16c76 100644 --- a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml +++ b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml @@ -152,9 +152,7 @@ DefaultModal { DefaultText { Layout.alignment: Qt.AlignHCenter - text_value: API.get().empty_string + (qsTr("Confirmations") + ": " + required_confirmation_count.value - + (required_confirmation_count.value === required_confirmation_count.default_confirmation_count ? - " (" + qsTr("Recommended") + ")" : "")) + text_value: API.get().empty_string + (qsTr("Confirmations") + ": " + required_confirmation_count.value) } Slider { From a62b9134afa1f4de5efa987c4b242270aaa2af61 Mon Sep 17 00:00:00 2001 From: naezith Date: Thu, 6 Aug 2020 15:09:32 +0300 Subject: [PATCH 192/515] feat(gui): allow confirmation count setting for all coins --- .../qml/Exchange/Trade/ConfirmTradeModal.qml | 16 +++++++++------- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 6 ++++-- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml index a6f0d16c76..62bd1181fd 100644 --- a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml +++ b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml @@ -88,9 +88,7 @@ DefaultModal { ColumnLayout { id: config_section - readonly property bool is_configurable: API.get().get_coin_info(getTicker(!sell_mode)).type === "Smart Chain" - - visible: is_configurable + readonly property bool is_dpow_configurable: API.get().get_coin_info(getTicker(!sell_mode)).type === "Smart Chain" Layout.bottomMargin: 10 Layout.alignment: Qt.AlignHCenter @@ -116,6 +114,7 @@ DefaultModal { id: enable_dpow_confs Layout.alignment: Qt.AlignHCenter + visible: config_section.is_dpow_configurable checked: true onCheckedChanged: { if(checked) enable_normal_confs.checked = true @@ -125,6 +124,8 @@ DefaultModal { } DefaultText { + visible: enable_dpow_confs.visible + Layout.alignment: Qt.AlignHCenter text_value: API.get().empty_string + (General.cex_icon + " " + qsTr('Read more about dPoW')) wrapMode: Text.WordWrap @@ -139,7 +140,7 @@ DefaultModal { id: enable_normal_confs Layout.alignment: Qt.AlignHCenter - enabled: !enable_dpow_confs.checked + enabled: !is_dpow_configurable || !enable_dpow_confs.checked checked: true text: API.get().empty_string + (qsTr("Change required confirmations")) @@ -148,7 +149,7 @@ DefaultModal { // Normal configuration settings ColumnLayout { Layout.alignment: Qt.AlignHCenter - visible: !enable_dpow_confs.checked && enable_normal_confs.checked + visible: enable_normal_confs.enabled && enable_normal_confs.checked DefaultText { Layout.alignment: Qt.AlignHCenter @@ -171,7 +172,7 @@ DefaultModal { FloatingBackground { visible: enable_custom_config.visible && enable_custom_config.enabled && enable_custom_config.checked && - !enable_dpow_confs.checked + (config_section.is_dpow_configurable && !enable_dpow_confs.checked) Layout.alignment: Qt.AlignHCenter Layout.bottomMargin: 10 @@ -206,7 +207,8 @@ DefaultModal { Layout.fillWidth: true onClicked: { trade(getTicker(true), getTicker(false), { - enable_custom_config: config_section.is_configurable && enable_custom_config.checked, + enable_custom_config: enable_custom_config.checked, + is_dpow_configurable: config_section.is_dpow_configurable, enable_dpow_confs: enable_dpow_confs.checked, enable_normal_confs: enable_normal_confs.checked, normal_configuration: { diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index 50dbbc8588..15d56e1fd4 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -276,9 +276,11 @@ Item { let confs = "" console.log("Trade config: ", JSON.stringify(options)) if(options.enable_custom_config) { - nota = options.enable_dpow_confs ? "1" : "0" + if(options.is_dpow_configurable) { + nota = options.enable_dpow_confs ? "1" : "0" + } - if(!options.enable_dpow_confs && options.enable_normal_confs) { + if(nota !== "1" && options.enable_normal_confs) { confs = options.normal_configuration.required_confirmation_count.toString() } } From 4dd366c1b1e29613b57a8a90b91fec3ff1fac3ce Mon Sep 17 00:00:00 2001 From: naezith Date: Thu, 6 Aug 2020 15:33:39 +0300 Subject: [PATCH 193/515] feat(gui): show default config values --- .../qml/Exchange/Trade/ConfirmTradeModal.qml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml index 62bd1181fd..ab656bf058 100644 --- a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml +++ b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml @@ -105,7 +105,7 @@ DefaultModal { // Configuration settings ColumnLayout { id: custom_config - visible: enable_custom_config.checked + enabled: enable_custom_config.checked Layout.alignment: Qt.AlignHCenter @@ -124,8 +124,7 @@ DefaultModal { } DefaultText { - visible: enable_dpow_confs.visible - + visible: enable_dpow_confs.visible && enable_dpow_confs.enabled Layout.alignment: Qt.AlignHCenter text_value: API.get().empty_string + (General.cex_icon + " " + qsTr('Read more about dPoW')) wrapMode: Text.WordWrap @@ -140,7 +139,8 @@ DefaultModal { id: enable_normal_confs Layout.alignment: Qt.AlignHCenter - enabled: !is_dpow_configurable || !enable_dpow_confs.checked + visible: !config_section.is_dpow_configurable || !enable_dpow_confs.checked + enabled: !config_section.is_dpow_configurable || !enable_dpow_confs.checked checked: true text: API.get().empty_string + (qsTr("Change required confirmations")) @@ -149,11 +149,13 @@ DefaultModal { // Normal configuration settings ColumnLayout { Layout.alignment: Qt.AlignHCenter - visible: enable_normal_confs.enabled && enable_normal_confs.checked + visible: enable_normal_confs.visible && enable_normal_confs.checked + enabled: enable_normal_confs.enabled && enable_normal_confs.checked DefaultText { Layout.alignment: Qt.AlignHCenter text_value: API.get().empty_string + (qsTr("Confirmations") + ": " + required_confirmation_count.value) + color: parent.enabled ? Style.colorText : Style.colorTextDisabled } Slider { From 263b32821c5c2c763cd67e3b23ee3a6824549b3d Mon Sep 17 00:00:00 2001 From: naezith Date: Thu, 6 Aug 2020 17:19:51 +0300 Subject: [PATCH 194/515] feat(gui): hide config part --- atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml index ab656bf058..da9d4913bc 100644 --- a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml +++ b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml @@ -98,14 +98,13 @@ DefaultModal { Layout.alignment: Qt.AlignHCenter id: enable_custom_config - enabled: parent.visible text: API.get().empty_string + (qsTr("Use custom protection settings for incoming %1 transactions", "TICKER").arg(getTicker(!sell_mode))) } // Configuration settings ColumnLayout { id: custom_config - enabled: enable_custom_config.checked + visible: enable_custom_config.checked Layout.alignment: Qt.AlignHCenter From 067dc505747c5ac3ff4f5796eb18268c77994fd5 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Thu, 6 Aug 2020 16:38:14 +0200 Subject: [PATCH 195/515] enhancements(mm2): adding raw cfg file --- .../assets/languages/atomic_qt_en.ts | 590 ++++++++++------- .../assets/languages/atomic_qt_fr.ts | 614 ++++++++++++------ .../assets/languages/atomic_qt_tr.ts | 608 +++++++++++------ atomic_qt_design/qml/Constants/Style.qml | 2 +- src/atomic.dex.mm2.hpp | 20 +- src/atomic.dex.raw.mm2.coins.cfg.hpp | 227 +++++++ 6 files changed, 1392 insertions(+), 669 deletions(-) create mode 100644 src/atomic.dex.raw.mm2.coins.cfg.hpp diff --git a/atomic_qt_design/assets/languages/atomic_qt_en.ts b/atomic_qt_design/assets/languages/atomic_qt_en.ts index 0d854f65ea..9d28c02d8b 100644 --- a/atomic_qt_design/assets/languages/atomic_qt_en.ts +++ b/atomic_qt_design/assets/languages/atomic_qt_en.ts @@ -19,26 +19,34 @@ - + Enter the contact name - + Enter the address - + Explorer - + Send + + CandleStickChart + + + There is no chart data for this pair yet + + + ClaimRewardsModal @@ -72,27 +80,57 @@ ConfirmTradeModal - + Confirm Exchange Details - + This swap request can not be undone and is a final event! - + This transaction can take up to 10 mins - DO NOT close this application! - + + Enable Komodo dPoW security + + + + + Enable Notarization + + + + + Change required confirmations + + + + + Confirmations + + + + + Recommended + + + + + Warning, this atomic swap is not dPoW/blockchain confirmation protected + + + + Cancel - + Confirm @@ -108,22 +146,22 @@ Dashboard - + News - + Dapps - + CEX Data - + Markets data (prices, charts, etc.) marked with the ⓘ icon originates from third party sources. (<a href="https://coinpaprika.com">coinpaprika.com</a>) @@ -131,38 +169,38 @@ DeleteWalletModal - + Delete Wallet - + Are you sure you want to delete %1 wallet? WALLET_NAME - + If so, make sure you record your seed phrase in order to restore your wallet in future. - + Enter the password of your wallet - + Wrong Password - + Cancel - + Delete @@ -170,42 +208,42 @@ EnableCoinModal - + Enable coins - + Search - + Select all UTXO coins - + Select all SmartChains - + Select all ERC tokens - + All coins are already enabled! - + Close - + Enable @@ -284,45 +322,55 @@ Exchange - + Trade - + Orders - + History - + Order Matching - + Order Matched - + Swap Ongoing - + Swap Successful - + + Refunding + + + + Swap Failed + + + Unknown State + + FirstLaunch @@ -350,12 +398,12 @@ History - + Recent Swaps - + Recover Funds Result @@ -400,7 +448,7 @@ - + Login @@ -433,58 +481,58 @@ - + %1 / %2 Price TICKER - + Volume 24h - + Address Book - + Send - + Receive - + Swap - + Claim Rewards - + Loading - + Scanning blocks for TX History... - + Syncing TX History... - + No transactions @@ -497,63 +545,63 @@ - + Failed to create a wallet - + New User - + Important: Back up your seed phrase before proceeding! - + We recommend storing it offline. - + Generated Seed - + Confirm Seed - + Enter the generated seed here - + Back - - + + Continue - + Let's double check your seed phrase - + Your seed phrase is important - that's why we like to make sure it's correct. We'll ask you three different questions about your seed phrase to make sure you'll be able to easily restore your wallet whenever you want. - + What's the %n. word in your seed phrase? @@ -561,7 +609,7 @@ - + Enter the %n. word @@ -569,7 +617,7 @@ - + Go back and check again @@ -577,45 +625,50 @@ NoConnection - + No connection - + Please make sure you are connected to the internet - - - OrderContent - - Swap ID + + Will automatically retry in %1 seconds + + + + + Retry + + + OrderContent - - UUID + + ID - + Maker Order - + Taker Order - + Cancel - + Recover Funds @@ -623,68 +676,80 @@ OrderForm - + Sell - - Receive + + Amount to sell - - Amount + + Amount to receive - - Amount to sell + + Buy - - Amount to receive + + Price - - Please fill the send amount + + Volume - + Min - + Half - + Max - + Transaction Fee - + Trading Fee - + Fees will be calculated - - Trade + + Total + + + + + Sell %1 + TICKER + + + + + Buy %1 + TICKER @@ -699,186 +764,140 @@ OrderModal - + Swap Details - + Order Details - + Maker Order - + Taker Order - + Refund State - + Your swap failed but the auto-refund process for your payment started already. Please wait and keep application opened until you receive your payment back - + Date - - Swap ID - - - - - UUID - - - - + Maker Payment Sent ID - + Maker Payment Spent ID - + Taker Payment Spent ID - + Taker Payment Sent ID - + Cancel Order - + Error ID - - Error Log + + ID - - Close - - - - - View at Explorer - - - - - OrderReceiveModal - - - Receive - - - - - Search + + Error Log - - Click to create an order + + Close - - - Click to see %n order(s) - - - - - - - Close + + View at Explorer - OrderbookModal - - - Orderbook - - + OrderbookSection - - Price + + Ask Price - - Volume + + Bid Price - - Receive + + Quantity - - Close - - - - - Create your own order + + Total Orders - + Show All Coins - + Cancel All Orders - + Cancel All %1 Orders TICKER - + All %1 Orders TICKER - + All Orders @@ -996,33 +1015,38 @@ PriceLine - + + Fill the amounts to see the price information + + + + Exchange rate - + Selected - + Expensive - + Expedient - + %1 compared to CEX PRICE_DIFF% - + CEXchange rate @@ -1030,17 +1054,17 @@ ReceiveModal - + Receive - + Share this address to receive coins - + Close @@ -1048,39 +1072,39 @@ RecoverSeed - + Failed to recover the seed - + Recovery - - + + Seed - - + + Enter the seed - + Allow custom seed - + Back - + Confirm @@ -1088,37 +1112,37 @@ RecoverSeedModal - + View Seed - + Please enter your password to view the seed. - + Wrong Password - + Seed - + Cancel - + Close - + View @@ -1144,140 +1168,140 @@ SendModal - + Prepare to Send - - + + Recipient's address - + Enter address of the recipient - + Address Book - + The address has to be mixed case. - + Fix - + Amount to send - + Enter the amount to send - + MAX - + Enable Custom Fees - + Only use custom fees if you know what you are doing! - + Custom Fee - + Enter the custom fee - + Gas Limit - + Enter the gas limit - + Gas Price - + Enter the gas price - + Custom Fee can't be higher than the amount - + Not enough funds. - + You have %1 AMT TICKER - + Close - + Prepare - - + + Send - + Amount - + Fees - + Date - + Back @@ -1366,7 +1390,7 @@ Sidebar - + Disable %1 TICKER @@ -1421,6 +1445,14 @@ + + TextFieldWithTitle + + + Required + + + Toast @@ -1432,44 +1464,54 @@ Trade - + No balance available - + Please enable a coin with balance or deposit funds - + Placed the order - + Failed to place the order - + + Please fill the price field + + + + + %1 balance is lower than minimum trade amount + + + + Not enough balance for the fees. Need at least %1 more AMT TICKER - - Not enough ETH for the transaction fee + + Please fill the volume field - - Sell amount is lower than minimum trade amount + + Not enough ETH for the transaction fee - - Receive amount is lower than minimum trade amount + + Amount is lower than minimum trade amount @@ -1549,16 +1591,72 @@ - + transaction fee - + Unconfirmed + + UpdateModal + + + Available + + + + + Required + + + + + Recommended + + + + + New Update! + + + + + Problem occured + + + + + Skip + + + + + Download + + + + + UpdateNotificationLine + + + New update available! + + + + + Version: + + + + + Click here for the details. + + + WalletNameField diff --git a/atomic_qt_design/assets/languages/atomic_qt_fr.ts b/atomic_qt_design/assets/languages/atomic_qt_fr.ts index 5ba4de8418..5b2370a51e 100644 --- a/atomic_qt_design/assets/languages/atomic_qt_fr.ts +++ b/atomic_qt_design/assets/languages/atomic_qt_fr.ts @@ -19,22 +19,22 @@ - + Enter the contact name - + Enter the address - + Explorer - + Send Envoyez @@ -46,6 +46,14 @@ version de la gui + + CandleStickChart + + + There is no chart data for this pair yet + + + ClaimRewardsModal @@ -79,27 +87,57 @@ ConfirmTradeModal - + Confirm Exchange Details Détails de la confirmation de l'échange - + This swap request can not be undone and is a final event! La requête de ce swap ne peut pas être annulé, c'est irréversible ! - + This transaction can take up to 10 mins - DO NOT close this application! Cette transaction peut prendre jusqu'à 10 mins - NE fermez pas l'application ! - + + Enable Komodo dPoW security + + + + + Enable Notarization + + + + + Change required confirmations + + + + + Confirmations + Confirmations + + + + Recommended + + + + + Warning, this atomic swap is not dPoW/blockchain confirmation protected + + + + Cancel Annuler - + Confirm Confirmer @@ -115,22 +153,22 @@ Dashboard - + News Actualités - + Dapps - + CEX Data - + Markets data (prices, charts, etc.) marked with the ⓘ icon originates from third party sources. (<a href="https://coinpaprika.com">coinpaprika.com</a>) @@ -142,38 +180,38 @@ DeleteWalletModal - + Delete Wallet Supprimez votre portefeuille - + Are you sure you want to delete %1 wallet? WALLET_NAME Êtes-vous sûre de supprimez le portefeuille %1 ? - + If so, make sure you record your seed phrase in order to restore your wallet in future. Si c'est le cas, faite en sorte que votre phrase de récupération soit sauvegardée pour pouvoir restaurer votre portefeuille à l'avenir. - + Enter the password of your wallet Entrez le mot de passe de votre portefeuille - + Wrong Password Mauvais mot de passe - + Cancel Annuler - + Delete Supprimez @@ -181,42 +219,42 @@ EnableCoinModal - + Enable coins Activer les pièces - + Search Rechercher - + Select all UTXO coins Selectionnez toutes les pièces UTXO - + Select all SmartChains Selectionnez toutes les SmartChains - + Select all ERC tokens Selectionnez tous les jetons ERC - + All coins are already enabled! Toutes les pièces sont déjà activées ! - + Close Fermer - + Enable Activer @@ -295,45 +333,55 @@ Exchange - + Trade Échanger - + Orders Ordres - + History Historique - + Order Matching Recherche d'un ordre - + Order Matched Ordre trouvé - + Swap Ongoing Échange en cours - + Swap Successful Échange terminé - + + Refunding + + + + Swap Failed Erreur lors de l'échange + + + Unknown State + + FirstLaunch @@ -365,12 +413,12 @@ History - + Recent Swaps Swaps récents - + Recover Funds Result Le résultat de la récupération des fonds @@ -415,7 +463,7 @@ - + Login Connection @@ -448,58 +496,58 @@ - + %1 / %2 Price TICKER - + Volume 24h - + Address Book - + Send Envoyez - + Receive Recevoir - + Swap Échange - + Claim Rewards Réclamer des récompenses - + Loading Chargement - + Scanning blocks for TX History... - + Syncing TX History... - + No transactions Pas de transactions @@ -512,63 +560,63 @@ Mauvais mot, veuillez vérifier à nouveau - + Failed to create a wallet Impossible de créer un portefeuille - + New User Nouvel utilisateur - + Important: Back up your seed phrase before proceeding! Important: sauvegardez votre phrase de recupération avant de continuer ! - + We recommend storing it offline. Nous vous recommandons de le stocker hors ligne. - + Generated Seed Générer un Seed - + Confirm Seed Confirmer la phrase de récupération - + Enter the generated seed here Veuillez entrez la phrase de récupération ici - + Back Retour - - + + Continue Continuer - + Let's double check your seed phrase Vérifions à nouveau votre phrase de récupération - + Your seed phrase is important - that's why we like to make sure it's correct. We'll ask you three different questions about your seed phrase to make sure you'll be able to easily restore your wallet whenever you want. Votre phrase de récupération est importante - c'est pourquoi nous aimons nous assurer qu'elle est correcte. Nous vous poserons trois questions différentes au sujet de votre phrase source pour vous assurer que vous pourrez facilement restaurer votre portefeuille à tout moment. - + What's the %n. word in your seed phrase? Quel est le mot numéro %n dans votre phrase de récupération ? @@ -576,7 +624,7 @@ - + Enter the %n. word Entrez le mot numéro %n @@ -584,7 +632,7 @@ - + Go back and check again Revenez en arrière et vérifiez à nouveau @@ -596,45 +644,69 @@ NoConnection - + No connection Pas de connéction - + Please make sure you are connected to the internet Veuillez vous assurer que vous êtes connecté à Internet + + + Will automatically retry in %1 seconds + + + + + Retry + + + + + NotificationsPanel + + AtomicDEX Pro + AtomicDEX Pro + + + Close + Fermer + OrderContent - Swap ID - Identifiant du Swap + Identifiant du Swap - UUID - UUID + UUID + + + + ID + - + Maker Order Ordre de vente - + Taker Order Ordre d'achat - + Cancel Annuler - + Recover Funds Récupérer des fonds @@ -642,73 +714,101 @@ OrderForm - + Sell Vendre - Receive - Recevoir + Recevoir MAX MAX - Amount - Montant + Montant - + Amount to sell Montant à vendre - + Amount to receive Montant à recevoir - Please fill the send amount - Veuillez remplir le montant de la vente + Veuillez remplir le montant de la vente + + + + Buy + - + + Price + Prix + + + + Volume + Volume + + + Min - + Half - + Max - + Transaction Fee Frais de transactions - + Trading Fee Frais d'échanges - + Fees will be calculated - + + Total + + + + + Sell %1 + TICKER + + + + + Buy %1 + TICKER + + + Trade - Échanger + Échanger @@ -745,72 +845,75 @@ OrderModal - + Swap Details Détails de l'échange - + Order Details Détails de l'ordre - + Maker Order Ordre de vente - + Taker Order Ordre d'achat - + Refund State - + Your swap failed but the auto-refund process for your payment started already. Please wait and keep application opened until you receive your payment back - + Date Date - + + ID + + + Swap ID - Identifiant du Swap + Identifiant du Swap - UUID - UUID + UUID - + Maker Payment Sent ID - + Maker Payment Spent ID - + Taker Payment Spent ID - + Taker Payment Sent ID - + Cancel Order @@ -823,17 +926,17 @@ ID du paiement du vendeur - + Error ID ID de l'erreur - + Error Log Journal des erreurs - + Close Fermer @@ -842,7 +945,7 @@ Annuler - + View at Explorer Voir dans l'explorateur @@ -850,93 +953,105 @@ OrderReceiveModal - Receive - Recevoir + Recevoir - Search - Rechercher + Rechercher - Click to create an order - Cliquez pour créer un ordre + Cliquez pour créer un ordre - Click to see %n order(s) - + Cliquez pour voir %n ordre (s) Cliquez pour voir %n ordre (s) - Close - Fermer + Fermer OrderbookModal - Orderbook - Carnet d'ordres + Carnet d'ordres - Price - Prix + Prix - Volume - Volume + Volume - Receive - Recevoir + Recevoir - Close - Fermer + Fermer - Create your own order - Créez votre propre ordre + Créez votre propre ordre + + + + OrderbookSection + + + Ask Price + + + + + Bid Price + + + + + Quantity + + + + + Total + Orders - + Show All Coins - + Cancel All Orders Annuler tous les ordres - + Cancel All %1 Orders TICKER - + All %1 Orders TICKER Tous les ordres %1 - + All Orders @@ -1062,33 +1177,38 @@ Prix ​​sélectionné - + + Fill the amounts to see the price information + + + + Exchange rate - + Selected - + Expensive - + Expedient - + %1 compared to CEX PRICE_DIFF% - + CEXchange rate @@ -1096,17 +1216,17 @@ ReceiveModal - + Receive Recevoir - + Share this address to receive coins Partagez cette adresse pour recevoir des pièces - + Close Fermer @@ -1114,39 +1234,39 @@ RecoverSeed - + Failed to recover the seed Impossible de récupérer la phrase de récupération - + Recovery Récupération - - + + Seed Phrase de récupération - - + + Enter the seed Entrez la phrase de récupération - + Allow custom seed Autoriser les phrases de récupération personnalisées - + Back Retour - + Confirm Confirmer @@ -1154,37 +1274,37 @@ RecoverSeedModal - + View Seed Voir la phrase de récupération - + Please enter your password to view the seed. Veuillez entrer votre mot de passe pour voir la phrase de récupération. - + Wrong Password Mauvais mot de passe - + Seed Phrase de récupération - + Cancel Annuler - + Close Fermer - + View Voir @@ -1210,140 +1330,140 @@ SendModal - + Prepare to Send Préparez-pour l'envoie - - + + Recipient's address Adresse du destinataire - + Enter address of the recipient Entrez l'adresse du destinataire - + Address Book - + The address has to be mixed case. L'adresse doit être mixte (case). - + Fix Réparer - + Amount to send Montant à envoyer - + Enter the amount to send Entrez le montant à envoyer - + MAX MAX - + Enable Custom Fees Activer les frais personnalisés - + Only use custom fees if you know what you are doing! N'utilisez des frais personnalisés que si vous savez ce que vous faites ! - + Custom Fee Frais personnalisés - + Enter the custom fee Entrez les frais personnalisées - + Gas Limit Limite de gaz - + Enter the gas limit Entrez la limite de gaz - + Gas Price Prix ​​du gaz - + Enter the gas price Entrez le prix du gaz - + Custom Fee can't be higher than the amount Les frais personnalisées ne peuvent pas être supérieurs au montant - + Not enough funds. Pas assez de fonds. - + You have %1 AMT TICKER Vous avez %1 - + Close Fermer - + Prepare Préparer - - + + Send Envoyez - + Amount Montant - + Fees Frais - + Date Date - + Back Retour @@ -1460,7 +1580,7 @@ Réglages - + Disable %1 TICKER @@ -1515,6 +1635,14 @@ Vous n'avez pas d'ordres récents. + + TextFieldWithTitle + + + Required + + + Toast @@ -1526,12 +1654,12 @@ Trade - + No balance available Aucun solde disponible - + Please enable a coin with balance or deposit funds Veuillez activer une pièce avec solde ou déposez des fonds @@ -1544,35 +1672,53 @@ Impossible de placer l'ordre. - + Placed the order - + Failed to place the order - + + Please fill the price field + + + + + %1 balance is lower than minimum trade amount + + + + Not enough balance for the fees. Need at least %1 more AMT TICKER - + + Please fill the volume field + + + + Not enough ETH for the transaction fee Pas assez d'ETH pour les frais de transaction - + + Amount is lower than minimum trade amount + + + Sell amount is lower than minimum trade amount - Le montant de la vente est inférieur au montant minimum de l'échange + Le montant de la vente est inférieur au montant minimum de l'échange - Receive amount is lower than minimum trade amount - Le montant reçu est inférieur au montant minimum de l'échange + Le montant reçu est inférieur au montant minimum de l'échange @@ -1651,16 +1797,72 @@ - + transaction fee - + Unconfirmed + + UpdateModal + + + Available + + + + + Required + + + + + Recommended + + + + + New Update! + + + + + Problem occured + + + + + Skip + + + + + Download + + + + + UpdateNotificationLine + + + New update available! + + + + + Version: + + + + + Click here for the details. + + + Wallet diff --git a/atomic_qt_design/assets/languages/atomic_qt_tr.ts b/atomic_qt_design/assets/languages/atomic_qt_tr.ts index cb97a4d07d..c8439ea929 100644 --- a/atomic_qt_design/assets/languages/atomic_qt_tr.ts +++ b/atomic_qt_design/assets/languages/atomic_qt_tr.ts @@ -19,22 +19,22 @@ - + Enter the contact name - + Enter the address - + Explorer - + Send Gönder @@ -50,6 +50,14 @@ gui versiyonu + + CandleStickChart + + + There is no chart data for this pair yet + + + ClaimRewardsModal @@ -83,27 +91,57 @@ ConfirmTradeModal - + Confirm Exchange Details Al-Sat Detaylarını Onayla - + This swap request can not be undone and is a final event! Bu takas isteği geri döndürülemez! - + This transaction can take up to 10 mins - DO NOT close this application! Bu işlem 10 dakika kadar sürebilir - Programı KAPATMAYINIZ! - + + Enable Komodo dPoW security + + + + + Enable Notarization + + + + + Change required confirmations + + + + + Confirmations + Onay Sayısı + + + + Recommended + + + + + Warning, this atomic swap is not dPoW/blockchain confirmation protected + + + + Cancel İptal - + Confirm Onayla @@ -119,22 +157,22 @@ Dashboard - + News Haberler - + Dapps - + CEX Data - + Markets data (prices, charts, etc.) marked with the ⓘ icon originates from third party sources. (<a href="https://coinpaprika.com">coinpaprika.com</a>) @@ -146,38 +184,38 @@ DeleteWalletModal - + Delete Wallet Cüzdanı Sil - + Are you sure you want to delete %1 wallet? WALLET_NAME %1 cüzdanınızı silmek istediğinizden emin misiniz? - + If so, make sure you record your seed phrase in order to restore your wallet in future. Öyleyse, cüzdanınızı gelecekte kurtarabilmeniz için seed satırınızı kaydettiğinizden emin olunuz. - + Enter the password of your wallet Cüzdanınızın şifresini giriniz - + Wrong Password Yanlış Parola - + Cancel İptal - + Delete Sil @@ -185,42 +223,42 @@ EnableCoinModal - + Enable coins Kriptopara etkinleştir - + Search Ara - + Select all UTXO coins Tüm UTXO kriptoparaları seç - + Select all SmartChains Tüm SmartChain'leri seç - + Select all ERC tokens Tüm ERC tokenlarını seç - + All coins are already enabled! Tüm kriptoparalar zaten etkin! - + Close Kapat - + Enable Etkinleştir @@ -299,45 +337,55 @@ Exchange - + Trade Al-Sat - + Orders Emirler - + History Geçmiş - + Order Matching Emir Eşleşiyor - + Order Matched Emir Eşleşti - + Swap Ongoing Takas Devam Ediyor - + Swap Successful Takas Başarılı - + + Refunding + + + + Swap Failed Takas Başarısız + + + Unknown State + + FirstLaunch @@ -369,12 +417,12 @@ History - + Recent Swaps Son Takaslar - + Recover Funds Result @@ -419,7 +467,7 @@ - + Login Giriş @@ -452,58 +500,58 @@ - + %1 / %2 Price TICKER - + Volume 24h - + Address Book - + Send Gönder - + Receive - + Swap Takasla - + Claim Rewards Ödül Al - + Loading Yükleniyor - + Scanning blocks for TX History... - + Syncing TX History... - + No transactions İşlem yok @@ -516,77 +564,77 @@ Hatalı kelime, lütfen kontrol ediniz - + Failed to create a wallet Cüzdan oluşturulamadı - + New User Yeni Kullanıcı - + Important: Back up your seed phrase before proceeding! Önemli: Devam etmeden önce seed kelimelerinizi yedekleyin! - + We recommend storing it offline. Çevrimdışı saklamanızı öneririz. - + Generated Seed Seed Oluştur - + Confirm Seed Seed'i Onayla - + Enter the generated seed here Oluşturulmuş Seed'i buraya giriniz - + Back Geri - - + + Continue Devam - + Let's double check your seed phrase Seed kelimelerinizi tekrar kontrol edelim - + Your seed phrase is important - that's why we like to make sure it's correct. We'll ask you three different questions about your seed phrase to make sure you'll be able to easily restore your wallet whenever you want. Seed kelimeleriniz önemlidir - bu yüzden doğru olduğundan emin olmak istiyoruz. Cüzdanınızı istediğiniz zaman kolayca kurtarabileceğinizden emin olmak için seed kelimeleriniz hakkında üç farklı soru soracağız. - + What's the %n. word in your seed phrase? Seed kelimelerinizden %n. kelime nedir? - + Enter the %n. word %n. kelimeyi giriniz - + Go back and check again Geri dönüp tekrar kontrol et @@ -598,45 +646,69 @@ NoConnection - + No connection Bağlantı yok - + Please make sure you are connected to the internet Lütfen internete bağlı olduğunuzdan emin olun + + + Will automatically retry in %1 seconds + + + + + Retry + + + + + NotificationsPanel + + AtomicDEX Pro + AtomıcDEX Pro + + + Close + Kapat + OrderContent - Swap ID - Takas ID + Takas ID - UUID - UUID + UUID - + + ID + + + + Maker Order Yapıcı Emir - + Taker Order Alıcı Emir - + Cancel İptal - + Recover Funds @@ -644,73 +716,101 @@ OrderForm - + Sell Satılacak - Receive - Alınacak + Alınacak MAX MAKS - Amount - Miktar + Miktar - + Amount to sell Satılacak miktar - + Amount to receive Alınacak miktar - Please fill the send amount - Lütfen gönderilecek miktarı giriniz + Lütfen gönderilecek miktarı giriniz + + + + Buy + - + + Price + Fiyat + + + + Volume + Hacim + + + Min - + Half - + Max - + Transaction Fee İşlem Ücreti - + Trading Fee Al-Sat Ücreti - + Fees will be calculated - + + Total + + + + + Sell %1 + TICKER + + + + + Buy %1 + TICKER + + + Trade - Al-Sat + Al-Sat @@ -747,72 +847,75 @@ OrderModal - + Swap Details Takas Detayları - + Order Details Emir Detayları - + Maker Order Satıcı Emri - + Taker Order Alıcı Emri - + Refund State - + Your swap failed but the auto-refund process for your payment started already. Please wait and keep application opened until you receive your payment back - + Date Tarih - + + ID + + + Swap ID - Takas ID + Takas ID - UUID - UUID + UUID - + Maker Payment Sent ID - + Maker Payment Spent ID - + Taker Payment Spent ID - + Taker Payment Sent ID - + Cancel Order @@ -825,17 +928,17 @@ Alıcı Ödeme ID - + Error ID Hata ID - + Error Log Hata Kaydı - + Close Kapat @@ -844,7 +947,7 @@ İptal - + View at Explorer Explorer'da Görüntüle @@ -852,92 +955,104 @@ OrderReceiveModal - Receive - Al + Al - Search - Ara + Ara - Click to create an order - Emir oluşturmak için tıkla + Emir oluşturmak için tıkla - Click to see %n order(s) - + %n emri görüntüle - Close - Kapat + Kapat OrderbookModal - Orderbook - Emir Defteri + Emir Defteri - Price - Fiyat + Fiyat - Volume - Hacim + Hacim - Receive - Alınacak + Alınacak - Close - Kapat + Kapat - Create your own order - Kendi emrini oluştur + Kendi emrini oluştur + + + + OrderbookSection + + + Ask Price + + + + + Bid Price + + + + + Quantity + + + + + Total + Orders - + Show All Coins - + Cancel All Orders Tüm Emirleri İptal Et - + Cancel All %1 Orders TICKER - + All %1 Orders TICKER Tüm %1 Emirleri - + All Orders @@ -1063,33 +1178,38 @@ Seçilen Fiyat - + + Fill the amounts to see the price information + + + + Exchange rate - + Selected - + Expensive - + Expedient - + %1 compared to CEX PRICE_DIFF% - + CEXchange rate @@ -1097,17 +1217,17 @@ ReceiveModal - + Receive Al - + Share this address to receive coins Kriptopara almak için bu adresi paylaşın - + Close Kapat @@ -1115,39 +1235,39 @@ RecoverSeed - + Failed to recover the seed Seed kurtarılamadı - + Recovery Kurtarma - - + + Seed Seed - - + + Enter the seed Seed'i giriniz - + Allow custom seed - + Back Geri - + Confirm Onayla @@ -1155,37 +1275,37 @@ RecoverSeedModal - + View Seed Seed'i Gör - + Please enter your password to view the seed. Seed'i görmek için lütfen parolanızı giriniz. - + Wrong Password Yanlış Parola - + Seed Seed - + Cancel İptal - + Close Kapat - + View Gör @@ -1211,140 +1331,140 @@ SendModal - + Prepare to Send Gönderi Hazırlığı - - + + Recipient's address Alıcı adresi - + Enter address of the recipient Alıcının adresini giriniz - + Address Book - + The address has to be mixed case. - + Fix - + Amount to send Gönderilecek miktar - + Enter the amount to send Gönderilecek miktarı giriniz - + MAX MAKS - + Enable Custom Fees Özel Ücretleri Etkinleştir - + Only use custom fees if you know what you are doing! Özel ücretler hakkında bilginiz yoksa kullanmayınız! - + Custom Fee Özel Ücret - + Enter the custom fee Özel ücreti giriniz - + Gas Limit Gas Limiti - + Enter the gas limit Gas limitini giriniz - + Gas Price Gas Fiyatı - + Enter the gas price Gas fiyatını giriniz - + Custom Fee can't be higher than the amount Özel Ücret miktardan daha yüksek olamaz - + Not enough funds. Yetersiz bakiye. - + You have %1 AMT TICKER %1'niz var - + Close Kapat - + Prepare Hazırla - - + + Send Gönder - + Amount Miktar - + Fees Ücret - + Date Tarih - + Back Geri @@ -1465,7 +1585,7 @@ Ayarlar - + Disable %1 TICKER %1'i Etkinsizleştir @@ -1520,6 +1640,14 @@ Yakın zamanda bir emriniz yok. + + TextFieldWithTitle + + + Required + + + Toast @@ -1531,12 +1659,12 @@ Trade - + No balance available Bakiye yok - + Please enable a coin with balance or deposit funds Lütfen bakiyeniz bulunan bir kriptopara etkinleştirin ya da mevcut bakiyenizi doldurun @@ -1545,34 +1673,44 @@ Al-Sat - + Placed the order - + Failed to place the order - + + Please fill the price field + + + + + %1 balance is lower than minimum trade amount + + + + Not enough balance for the fees. Need at least %1 more AMT TICKER - - Not enough ETH for the transaction fee + + Please fill the volume field - - Sell amount is lower than minimum trade amount + + Not enough ETH for the transaction fee - - Receive amount is lower than minimum trade amount + + Amount is lower than minimum trade amount @@ -1664,16 +1802,72 @@ - + transaction fee - + Unconfirmed + + UpdateModal + + + Available + + + + + Required + + + + + Recommended + + + + + New Update! + + + + + Problem occured + + + + + Skip + + + + + Download + + + + + UpdateNotificationLine + + + New update available! + + + + + Version: + + + + + Click here for the details. + + + Wallet diff --git a/atomic_qt_design/qml/Constants/Style.qml b/atomic_qt_design/qml/Constants/Style.qml index 1cefe7b352..6d5745a804 100644 --- a/atomic_qt_design/qml/Constants/Style.qml +++ b/atomic_qt_design/qml/Constants/Style.qml @@ -7,7 +7,7 @@ QtObject { readonly property FontLoader mySystemFont: FontLoader { source: "../../assets/fonts/Montserrat-Regular.ttf" } readonly property FontLoader mySystemFontMedium: FontLoader { source: "../../assets/fonts/Montserrat-Medium.ttf" } readonly property FontLoader mySystemFontSemiBold: FontLoader { source: "../../assets/fonts/Montserrat-SemiBold.ttf" } - readonly property string font_family: "Montserrat" + readonly property string font_family: Qt.application.font.family readonly property string listItemPrefix: " ⚬ " readonly property string successCharacter: "✓" diff --git a/src/atomic.dex.mm2.hpp b/src/atomic.dex.mm2.hpp index 502e5c2ef8..f58abc032b 100644 --- a/src/atomic.dex.mm2.hpp +++ b/src/atomic.dex.mm2.hpp @@ -24,6 +24,7 @@ #include "atomic.dex.events.hpp" #include "atomic.dex.mm2.api.hpp" #include "atomic.dex.mm2.error.code.hpp" +#include "atomic.dex.raw.mm2.coins.cfg.hpp" #include "atomic.dex.utilities.hpp" namespace atomic_dex @@ -102,15 +103,16 @@ namespace atomic_dex std::string m_current_wallet_name; //! Concurrent Registry. - t_coins_registry& m_coins_informations{entity_registry_.set()}; - t_balance_registry& m_balance_informations{entity_registry_.set()}; - t_tx_history_registry m_tx_informations; - t_tx_state_registry m_tx_state; - t_my_orders m_orders_registry; - t_fees_registry m_trade_fees_registry; - t_orderbook_registry m_current_orderbook; - t_swaps_registry m_swaps_registry; - t_swaps_avrg_datas m_swaps_avrg_registry; + t_coins_registry& m_coins_informations{entity_registry_.set()}; + t_balance_registry& m_balance_informations{entity_registry_.set()}; + t_tx_history_registry m_tx_informations; + t_tx_state_registry m_tx_state; + t_my_orders m_orders_registry; + t_fees_registry m_trade_fees_registry; + t_orderbook_registry m_current_orderbook; + t_swaps_registry m_swaps_registry; + t_swaps_avrg_datas m_swaps_avrg_registry; + t_mm2_raw_coins_registry m_mm2_raw_coins_cfg{parse_raw_mm2_coins_file()}; //! Refresh the current orderbook (internally call process_orderbook) void fetch_current_orderbook_thread(bool is_a_reset = false); diff --git a/src/atomic.dex.raw.mm2.coins.cfg.hpp b/src/atomic.dex.raw.mm2.coins.cfg.hpp new file mode 100644 index 0000000000..bed221b1fb --- /dev/null +++ b/src/atomic.dex.raw.mm2.coins.cfg.hpp @@ -0,0 +1,227 @@ +#pragma once + +#include "atomic.dex.pch.hpp" + +#ifndef NLOHMANN_OPT_HELPER +# define NLOHMANN_OPT_HELPER +namespace nlohmann +{ + template + struct adl_serializer> + { + static void + to_json(json& j, const std::optional& opt) + { + if (opt.has_value()) + { + j = opt.value(); + } + } + + static std::optional + from_json(const json& j) + { + return j.is_null() ? std::optional{std::nullopt} : j.get(); + } + }; +} // namespace nlohmann +#endif + +namespace atomic_dex +{ + using nlohmann::json; + + inline json + get_untyped(const json& j, const char* property) + { + if (j.find(property) != j.end()) + { + return j.at(property).get(); + } + return json(); + } + + inline json + get_untyped(const json& j, std::string property) + { + return get_untyped(j, property.data()); + } + + template + inline std::optional + get_optional(const json& j, const char* property) + { + if (j.contains(property)) + { + return j.at(property).get>(); + } + return std::optional(); + } + + template + inline std::optional + get_optional(const json& j, std::string property) + { + return get_optional(j, property.data()); + } + + struct address_format + { + std::string format; + std::string network; + }; + + struct coin_element + { + std::string coin; + std::optional name; + std::optional fname; + std::optional etomic; + int64_t rpcport; + std::optional pubtype; + std::optional p2_shtype; + std::optional wiftype; + std::optional txfee; + std::optional confpath; + std::optional mm2; + std::optional required_confirmations; + std::optional asset; + std::optional txversion; + std::optional overwintered; + std::optional requires_notarization; + std::optional is_po_s; + std::optional segwit; + std::optional address_format; + std::optional estimate_fee_mode; + std::optional taddr; + std::optional decimals; + std::optional force_min_relay_fee; + std::optional p2_p; + std::optional magic; + std::optional n_spv; + std::optional version_group_id; + std::optional consensus_branch_id; + }; + + using coins = std::vector; +} // namespace atomic_dex + +namespace atomic_dex +{ + using t_mm2_raw_coins = std::vector; + using t_mm2_raw_coins_registry = std::unordered_map; +} // namespace atomic_dex + +namespace atomic_dex +{ + void from_json(const json& j, atomic_dex::address_format& x); + void to_json(json& j, const atomic_dex::address_format& x); + + void from_json(const json& j, atomic_dex::coin_element& x); + void to_json(json& j, const atomic_dex::coin_element& x); + + inline void + from_json(const json& j, atomic_dex::address_format& x) + { + x.format = j.at("format").get(); + x.network = j.at("network").get(); + } + + inline void + to_json(json& j, const atomic_dex::address_format& x) + { + j = json::object(); + j["format"] = x.format; + j["network"] = x.network; + } + + inline void + from_json(const json& j, atomic_dex::coin_element& x) + { + x.coin = j.at("coin").get(); + x.name = atomic_dex::get_optional(j, "name"); + x.fname = atomic_dex::get_optional(j, "fname"); + x.etomic = atomic_dex::get_optional(j, "etomic"); + x.rpcport = j.at("rpcport").get(); + x.pubtype = atomic_dex::get_optional(j, "pubtype"); + x.p2_shtype = atomic_dex::get_optional(j, "p2shtype"); + x.wiftype = atomic_dex::get_optional(j, "wiftype"); + x.txfee = atomic_dex::get_optional(j, "txfee"); + x.confpath = atomic_dex::get_optional(j, "confpath"); + x.mm2 = atomic_dex::get_optional(j, "mm2"); + x.required_confirmations = atomic_dex::get_optional(j, "required_confirmations"); + x.asset = atomic_dex::get_optional(j, "asset"); + x.txversion = atomic_dex::get_optional(j, "txversion"); + x.overwintered = atomic_dex::get_optional(j, "overwintered"); + x.requires_notarization = atomic_dex::get_optional(j, "requires_notarization"); + x.is_po_s = atomic_dex::get_optional(j, "isPoS"); + x.segwit = atomic_dex::get_optional(j, "segwit"); + x.address_format = atomic_dex::get_optional(j, "address_format"); + x.estimate_fee_mode = atomic_dex::get_optional(j, "estimate_fee_mode"); + x.taddr = atomic_dex::get_optional(j, "taddr"); + x.decimals = atomic_dex::get_optional(j, "decimals"); + x.force_min_relay_fee = atomic_dex::get_optional(j, "force_min_relay_fee"); + x.p2_p = atomic_dex::get_optional(j, "p2p"); + x.magic = atomic_dex::get_optional(j, "magic"); + x.n_spv = atomic_dex::get_optional(j, "nSPV"); + x.version_group_id = atomic_dex::get_optional(j, "version_group_id"); + x.consensus_branch_id = atomic_dex::get_optional(j, "consensus_branch_id"); + } + + inline void + to_json(json& j, const atomic_dex::coin_element& x) + { + j = json::object(); + j["coin"] = x.coin; + j["name"] = x.name; + j["fname"] = x.fname; + j["etomic"] = x.etomic; + j["rpcport"] = x.rpcport; + j["pubtype"] = x.pubtype; + j["p2shtype"] = x.p2_shtype; + j["wiftype"] = x.wiftype; + j["txfee"] = x.txfee; + j["confpath"] = x.confpath; + j["mm2"] = x.mm2; + j["required_confirmations"] = x.required_confirmations; + j["asset"] = x.asset; + j["txversion"] = x.txversion; + j["overwintered"] = x.overwintered; + j["requires_notarization"] = x.requires_notarization; + j["isPoS"] = x.is_po_s; + j["segwit"] = x.segwit; + j["address_format"] = x.address_format; + j["estimate_fee_mode"] = x.estimate_fee_mode; + j["taddr"] = x.taddr; + j["decimals"] = x.decimals; + j["force_min_relay_fee"] = x.force_min_relay_fee; + j["p2p"] = x.p2_p; + j["magic"] = x.magic; + j["nSPV"] = x.n_spv; + j["version_group_id"] = x.version_group_id; + j["consensus_branch_id"] = x.consensus_branch_id; + } + + inline t_mm2_raw_coins_registry + parse_raw_mm2_coins_file() + { + t_mm2_raw_coins_registry out; + fs::path file_path{ag::core::assets_real_path() / "tools" / "mm2" / "coins"}; + std::ifstream ifs(file_path.string()); + assert(ifs.is_open()); + try + { + nlohmann::json j; + ifs >> j; + t_mm2_raw_coins coins = j; + out.reserve(coins.size()); + for (auto&& coin: coins) { out[coin.coin] = coin; } + spdlog::info("successfully parsed: {}, nb_coins: {}", file_path.string(), out.size()); + } + catch (const std::exception& error) + { + spdlog::error("cannot parse mm2 raw cfg file: {} {}", file_path.string(), error.what()); + } + return out; + } +} // namespace atomic_dex From b53245b6a64c583e6123aef4149ef237a7c42bfb Mon Sep 17 00:00:00 2001 From: naezith Date: Thu, 6 Aug 2020 20:48:29 +0300 Subject: [PATCH 196/515] feat(gui): show default trade config --- atomic_qt_design/qml/Constants/Style.qml | 2 +- .../qml/Exchange/Trade/ConfirmTradeModal.qml | 25 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/atomic_qt_design/qml/Constants/Style.qml b/atomic_qt_design/qml/Constants/Style.qml index 6d5745a804..1cefe7b352 100644 --- a/atomic_qt_design/qml/Constants/Style.qml +++ b/atomic_qt_design/qml/Constants/Style.qml @@ -7,7 +7,7 @@ QtObject { readonly property FontLoader mySystemFont: FontLoader { source: "../../assets/fonts/Montserrat-Regular.ttf" } readonly property FontLoader mySystemFontMedium: FontLoader { source: "../../assets/fonts/Montserrat-Medium.ttf" } readonly property FontLoader mySystemFontSemiBold: FontLoader { source: "../../assets/fonts/Montserrat-SemiBold.ttf" } - readonly property string font_family: Qt.application.font.family + readonly property string font_family: "Montserrat" readonly property string listItemPrefix: " ⚬ " readonly property string successCharacter: "✓" diff --git a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml index da9d4913bc..d41cccb0eb 100644 --- a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml +++ b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml @@ -85,6 +85,12 @@ DefaultModal { } } + HorizontalLine { + Layout.topMargin: 10 + Layout.bottomMargin: 10 + Layout.fillWidth: true + } + ColumnLayout { id: config_section @@ -93,6 +99,25 @@ DefaultModal { Layout.bottomMargin: 10 Layout.alignment: Qt.AlignHCenter + ColumnLayout { + Layout.alignment: Qt.AlignHCenter + visible: !enable_custom_config.checked + + DefaultText { + Layout.alignment: Qt.AlignHCenter + text_value: API.get().empty_string + (qsTr("Security configuration")) + font.bold: true + } + + DefaultText { + Layout.alignment: Qt.AlignHCenter + text_value: API.get().empty_string + ("✅ " + + (config_section.is_dpow_configurable ? qsTr("dPoW protected") : + qsTr("%1 confirmations for incoming transactions").arg(3))) + } + } + + // Enable custom config DefaultCheckBox { Layout.alignment: Qt.AlignHCenter From d88f41779793c04a7d509ddc74e0f7a2588fe899 Mon Sep 17 00:00:00 2001 From: naezith Date: Thu, 6 Aug 2020 20:53:29 +0300 Subject: [PATCH 197/515] =?UTF-8?q?feat(gui):=20WIP=20text=20instead=20of?= =?UTF-8?q?=20fixed=20number=20=F0=9F=8C=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml index d41cccb0eb..6619c091d9 100644 --- a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml +++ b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml @@ -86,7 +86,6 @@ DefaultModal { } HorizontalLine { - Layout.topMargin: 10 Layout.bottomMargin: 10 Layout.fillWidth: true } @@ -113,7 +112,7 @@ DefaultModal { Layout.alignment: Qt.AlignHCenter text_value: API.get().empty_string + ("✅ " + (config_section.is_dpow_configurable ? qsTr("dPoW protected") : - qsTr("%1 confirmations for incoming transactions").arg(3))) + qsTr("%1 confirmations for incoming transactions").arg("WIP"))) } } From 9c7339919267597b17d98b1ac9dc1988026134e6 Mon Sep 17 00:00:00 2001 From: naezith Date: Thu, 6 Aug 2020 23:05:31 +0300 Subject: [PATCH 198/515] feat(gui): add more notifications info --- atomic_qt_design/qml/Dashboard/NotificationsPanel.qml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml index 18d4964194..ad3fb8002c 100644 --- a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml +++ b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml @@ -35,11 +35,11 @@ FloatingBackground { } // Events - function onSwapStatusUpdated(old_swap_status, new_swap_status, swap_uuid) { + function onSwapStatusUpdated(old_swap_status, new_swap_status, swap_uuid, base_coin, rel_coin, human_date) { const obj = { - title: qsTr("Swap status updated"), + title: base_coin + "/" + rel_coin + " - " + qsTr("Swap status updated"), message: exchange.getStatusText(old_swap_status) + " " + General.right_arrow_icon + " " + exchange.getStatusText(new_swap_status), - time: Date.now() + time: human_date } if(!root.visible) @@ -118,7 +118,7 @@ FloatingBackground { anchors.topMargin: 10 anchors.right: parent.right anchors.rightMargin: 30 - text_value: API.get().empty_string + (General.timestampToString(modelData.time)) + text_value: API.get().empty_string + (modelData.time) font.pixelSize: Style.textSizeSmall } @@ -161,7 +161,7 @@ FloatingBackground { DefaultButton { text: API.get().empty_string + (qsTr("Pop Test Notification")) onClicked: { - onSwapStatusUpdated("ongoing", "finished", "123456") + onSwapStatusUpdated("ongoing", "finished", "123456", "BTC", "KMD", "13.3.1337") } } From e5d4895eb0c61b4bcb8f77ceff9702182789b7fa Mon Sep 17 00:00:00 2001 From: naezith Date: Fri, 7 Aug 2020 06:09:35 +0300 Subject: [PATCH 199/515] feat(gui): update existing notification --- .../qml/Dashboard/NotificationsPanel.qml | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml index ad3fb8002c..a2067de23d 100644 --- a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml +++ b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml @@ -37,16 +37,38 @@ FloatingBackground { // Events function onSwapStatusUpdated(old_swap_status, new_swap_status, swap_uuid, base_coin, rel_coin, human_date) { const obj = { + id: swap_uuid, title: base_coin + "/" + rel_coin + " - " + qsTr("Swap status updated"), message: exchange.getStatusText(old_swap_status) + " " + General.right_arrow_icon + " " + exchange.getStatusText(new_swap_status), time: human_date } + // Update if it already exists + let updated_existing_one = false + for(let i = 0; i < notifications_list.length; ++i) { + if(notifications_list[i].id === obj.id) { + notifications_list[i] = General.clone(obj) + updated_existing_one = true + break + } + } + + // Add new line + if(!updated_existing_one) { + notifications_list = [obj].concat(notifications_list) + } + + // Update unread notification count if(!root.visible) ++unread_notification_count - notifications_list = [obj].concat(notifications_list) + // Display OS notification displayMessage(obj.title, obj.message) + + // Refresh the list if updated an existing one + if(updated_existing_one) { + notifications_list = notifications_list + } } @@ -161,7 +183,7 @@ FloatingBackground { DefaultButton { text: API.get().empty_string + (qsTr("Pop Test Notification")) onClicked: { - onSwapStatusUpdated("ongoing", "finished", "123456", "BTC", "KMD", "13.3.1337") + onSwapStatusUpdated("ongoing", "finished", "123456", "BTC", "KMD", "13.3.1337" + Date.now().toString()) } } From 60759b186dd1bccd9fee15b9ba4c23cc916b5099 Mon Sep 17 00:00:00 2001 From: naezith Date: Fri, 7 Aug 2020 07:03:38 +0300 Subject: [PATCH 200/515] feat(gui): remove single notification button --- .../qml/Dashboard/NotificationsPanel.qml | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml index a2067de23d..afe3c4a98c 100644 --- a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml +++ b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml @@ -170,6 +170,36 @@ FloatingBackground { anchors.bottomMargin: -height/2 light: true } + + Rectangle { + radius: 100 + + width: height + height: remove_button.height * 1.2 + + anchors.bottom: parent.bottom + anchors.bottomMargin: 5 + anchors.right: parent.right + anchors.rightMargin: anchors.bottomMargin + + color: Style.colorTheme1 + + DefaultText { + id: remove_button + text_value: API.get().empty_string + ("✔️") + anchors.centerIn: parent + font.pixelSize: Style.textSizeSmall3 + color: Style.colorWhite10 + } + + MouseArea { + anchors.fill: parent + onClicked: { + notifications_list.splice(index, 1) + notifications_list = notifications_list + } + } + } } } } @@ -183,7 +213,7 @@ FloatingBackground { DefaultButton { text: API.get().empty_string + (qsTr("Pop Test Notification")) onClicked: { - onSwapStatusUpdated("ongoing", "finished", "123456", "BTC", "KMD", "13.3.1337" + Date.now().toString()) + onSwapStatusUpdated("ongoing", "finished", Date.now().toString(), "BTC", "KMD", "13.3.1337") } } From 3c64881ad4697e41c38f04ef47c8d9eca1ae3bea Mon Sep 17 00:00:00 2001 From: naezith Date: Fri, 7 Aug 2020 07:05:02 +0300 Subject: [PATCH 201/515] feat(gui): add mark all as read button --- .../qml/Dashboard/NotificationsPanel.qml | 40 +++++++++++++++++-- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml index afe3c4a98c..5544adbafc 100644 --- a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml +++ b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml @@ -101,10 +101,42 @@ FloatingBackground { spacing: 10 - DefaultText { - text_value: API.get().empty_string + (qsTr("Notifications")) - Layout.alignment: Qt.AlignLeft | Qt.AlignTop - font.pixelSize: Style.textSize2 + RowLayout { + Layout.fillWidth: true + Layout.alignment: Qt.AlignLeft | Qt.AlignBottom + DefaultText { + text_value: API.get().empty_string + (qsTr("Notifications")) + font.pixelSize: Style.textSize2 + Layout.fillWidth: true + Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter + } + + Rectangle { + radius: 3 + + width: mark_all_as_read.width + 10 + height: mark_all_as_read.height + 10 + + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + + color: Style.colorTheme1 + + DefaultText { + id: mark_all_as_read + text_value: API.get().empty_string + (qsTr("Mark all as read") + " ✔️") + font.pixelSize: Style.textSizeSmall3 + anchors.centerIn: parent + color: Style.colorWhite10 + } + + MouseArea { + anchors.fill: parent + onClicked: { + unread_notification_count = 0 + notifications_list = [] + } + } + } } HorizontalLine { From 42fbfdb1950779bd0bee706960d70822853311d3 Mon Sep 17 00:00:00 2001 From: naezith Date: Fri, 7 Aug 2020 07:10:48 +0300 Subject: [PATCH 202/515] feat(gui): move notifications icon to top right --- atomic_qt_design/qml/Screens/Dashboard.qml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/atomic_qt_design/qml/Screens/Dashboard.qml b/atomic_qt_design/qml/Screens/Dashboard.qml index 3d778dd182..e764859122 100644 --- a/atomic_qt_design/qml/Screens/Dashboard.qml +++ b/atomic_qt_design/qml/Screens/Dashboard.qml @@ -165,11 +165,14 @@ Item { } DefaultButton { - anchors.horizontalCenter: sidebar.horizontalCenter - anchors.bottom: sidebar.bottom - anchors.bottomMargin: 150 + anchors.top: parent.top + anchors.right: parent.right + anchors.topMargin: 5 + anchors.rightMargin: 5 + z: 1 text: "🔔" + font.pixelSize: Style.textSizeSmall3 minWidth: height onClicked: notifications_panel.visible = !notifications_panel.visible From 8cc2fbd0a568fcd247802fd68173f9dc70370848 Mon Sep 17 00:00:00 2001 From: naezith Date: Fri, 7 Aug 2020 07:29:55 +0300 Subject: [PATCH 203/515] feat(gui): move notifications panel to top right --- atomic_qt_design/qml/Dashboard/NotificationsPanel.qml | 2 +- atomic_qt_design/qml/Screens/Dashboard.qml | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml index 5544adbafc..153629d7e1 100644 --- a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml +++ b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml @@ -171,7 +171,7 @@ FloatingBackground { anchors.top: parent.top anchors.topMargin: 10 anchors.right: parent.right - anchors.rightMargin: 30 + anchors.rightMargin: 5 text_value: API.get().empty_string + (modelData.time) font.pixelSize: Style.textSizeSmall } diff --git a/atomic_qt_design/qml/Screens/Dashboard.qml b/atomic_qt_design/qml/Screens/Dashboard.qml index e764859122..d721f88a18 100644 --- a/atomic_qt_design/qml/Screens/Dashboard.qml +++ b/atomic_qt_design/qml/Screens/Dashboard.qml @@ -159,16 +159,17 @@ Item { id: notifications_panel width: 500 height: 500 - anchors.left: sidebar.right - anchors.bottom: parent.bottom - anchors.bottomMargin: -40 + anchors.right: notifications_button.right + anchors.top: notifications_button.bottom + anchors.topMargin: 8 } DefaultButton { + id: notifications_button anchors.top: parent.top anchors.right: parent.right - anchors.topMargin: 5 - anchors.rightMargin: 5 + anchors.topMargin: 8 + anchors.rightMargin: 8 z: 1 text: "🔔" From 8b7741aafce57e566c3bf63f0b0254a896bc0653 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Fri, 7 Aug 2020 14:06:45 +0200 Subject: [PATCH 204/515] feat(trading_modal): move buy/sell to trading modal page --- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 4 +- src/atomic.dex.app.cpp | 62 ------------------- src/atomic.dex.app.hpp | 6 -- src/atomic.dex.qt.trading.page.cpp | 61 ++++++++++++++++++ src/atomic.dex.qt.trading.page.hpp | 6 ++ 5 files changed, 69 insertions(+), 70 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index e18e94711d..894fc55ee7 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -302,9 +302,9 @@ Item { let result if(sell_mode) - result = API.get().place_sell_order(base, rel, price, volume, is_created_order, price_denom, price_numer, nota, confs) + result = API.get().trading_pg.place_sell_order(base, rel, price, volume, is_created_order, price_denom, price_numer, nota, confs) else - result = API.get().place_buy_order(base, rel, price, volume, is_created_order, price_denom, price_numer, nota, confs) + result = API.get().trading_pg.place_buy_order(base, rel, price, volume, is_created_order, price_denom, price_numer, nota, confs) if(result === "") { action_result = "success" diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index 7db37b3ec8..eb4b74e36f 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -592,68 +592,6 @@ namespace atomic_dex } } - QString - application::place_buy_order( - const QString& base, const QString& rel, const QString& price, const QString& volume, bool is_created_order, const QString& price_denom, - const QString& price_numer, const QString& base_nota, const QString& base_confs) - { - t_float_50 price_f; - t_float_50 amount_f; - t_float_50 total_amount; - - price_f.assign(price.toStdString()); - amount_f.assign(volume.toStdString()); - total_amount = price_f * amount_f; - - t_buy_request req{ - .base = base.toStdString(), - .rel = rel.toStdString(), - .price = price.toStdString(), - .volume = volume.toStdString(), - .is_created_order = is_created_order, - .price_denom = price_denom.toStdString(), - .price_numer = price_numer.toStdString(), - .base_nota = base_nota.isEmpty() ? std::optional{std::nullopt} : boost::lexical_cast(base_nota.toStdString()), - .base_confs = base_confs.isEmpty() ? std::optional{std::nullopt} : base_confs.toUInt()}; - std::error_code ec; - auto answer = get_mm2().place_buy_order(std::move(req), total_amount, ec); - - if (answer.error.has_value()) - { - return QString::fromStdString(answer.error.value()); - } - return ""; - } - - QString - application::place_sell_order( - const QString& base, const QString& rel, const QString& price, const QString& volume, bool is_created_order, const QString& price_denom, - const QString& price_numer, const QString& rel_nota, const QString& rel_confs) - { - qDebug() << " base: " << base << " rel: " << rel << " price: " << price << " volume: " << volume; - t_float_50 amount_f; - amount_f.assign(volume.toStdString()); - - t_sell_request req{ - .base = base.toStdString(), - .rel = rel.toStdString(), - .price = price.toStdString(), - .volume = volume.toStdString(), - .is_created_order = is_created_order, - .price_denom = price_denom.toStdString(), - .price_numer = price_numer.toStdString(), - .rel_nota = rel_nota.isEmpty() ? std::optional{std::nullopt} : boost::lexical_cast(rel_nota.toStdString()), - .rel_confs = rel_confs.isEmpty() ? std::optional{std::nullopt} : rel_confs.toUInt()}; - std::error_code ec; - auto answer = get_mm2().place_sell_order(std::move(req), amount_f, ec); - - if (answer.error.has_value()) - { - return QString::fromStdString(answer.error.value()); - } - return ""; - } - bool application::do_i_have_enough_funds(const QString& ticker, const QString& amount) const { diff --git a/src/atomic.dex.app.hpp b/src/atomic.dex.app.hpp index 365e0d26cd..8e4137f276 100644 --- a/src/atomic.dex.app.hpp +++ b/src/atomic.dex.app.hpp @@ -215,12 +215,6 @@ namespace atomic_dex Q_INVOKABLE bool enable_coins(const QStringList& coins); Q_INVOKABLE QString get_balance(const QString& coin); Q_INVOKABLE static QString get_price_amount(const QString& base_amount, const QString& rel_amount); - Q_INVOKABLE QString place_buy_order( - const QString& base, const QString& rel, const QString& price, const QString& volume, bool is_created_order, const QString& price_denom, - const QString& price_numer, const QString& base_nota = "", const QString& base_confs = ""); - Q_INVOKABLE QString place_sell_order( - const QString& base, const QString& rel, const QString& price, const QString& volume, bool is_created_order, const QString& price_denom, - const QString& price_numer, const QString& rel_nota = "", const QString& rel_confs = ""); Q_INVOKABLE bool do_i_have_enough_funds(const QString& ticker, const QString& amount) const; Q_INVOKABLE bool disable_coins(const QStringList& coins); Q_INVOKABLE bool is_claiming_ready(const QString& ticker); diff --git a/src/atomic.dex.qt.trading.page.cpp b/src/atomic.dex.qt.trading.page.cpp index 8aec9a3173..cad7dc969c 100644 --- a/src/atomic.dex.qt.trading.page.cpp +++ b/src/atomic.dex.qt.trading.page.cpp @@ -118,6 +118,67 @@ namespace atomic_dex mm2_system.process_orders(); }); } + + QString + trading_page::place_buy_order( + const QString& base, const QString& rel, const QString& price, const QString& volume, bool is_created_order, const QString& price_denom, + const QString& price_numer, const QString& base_nota, const QString& base_confs) + { + t_float_50 price_f; + t_float_50 amount_f; + t_float_50 total_amount; + + price_f.assign(price.toStdString()); + amount_f.assign(volume.toStdString()); + total_amount = price_f * amount_f; + + t_buy_request req{ + .base = base.toStdString(), + .rel = rel.toStdString(), + .price = price.toStdString(), + .volume = volume.toStdString(), + .is_created_order = is_created_order, + .price_denom = price_denom.toStdString(), + .price_numer = price_numer.toStdString(), + .base_nota = base_nota.isEmpty() ? std::optional{std::nullopt} : boost::lexical_cast(base_nota.toStdString()), + .base_confs = base_confs.isEmpty() ? std::optional{std::nullopt} : base_confs.toUInt()}; + std::error_code ec; + auto answer = m_system_manager.get_system().place_buy_order(std::move(req), total_amount, ec); + + if (answer.error.has_value()) + { + return QString::fromStdString(answer.error.value()); + } + return ""; + } + + QString + trading_page::place_sell_order( + const QString& base, const QString& rel, const QString& price, const QString& volume, bool is_created_order, const QString& price_denom, + const QString& price_numer, const QString& rel_nota, const QString& rel_confs) + { + t_float_50 amount_f; + amount_f.assign(volume.toStdString()); + + t_sell_request req{ + .base = base.toStdString(), + .rel = rel.toStdString(), + .price = price.toStdString(), + .volume = volume.toStdString(), + .is_created_order = is_created_order, + .price_denom = price_denom.toStdString(), + .price_numer = price_numer.toStdString(), + .rel_nota = rel_nota.isEmpty() ? std::optional{std::nullopt} : boost::lexical_cast(rel_nota.toStdString()), + .rel_confs = rel_confs.isEmpty() ? std::optional{std::nullopt} : rel_confs.toUInt()}; + std::error_code ec; + auto answer = m_system_manager.get_system().place_sell_order(std::move(req), amount_f, ec); + + if (answer.error.has_value()) + { + return QString::fromStdString(answer.error.value()); + } + return ""; + } } // namespace atomic_dex //! Public API diff --git a/src/atomic.dex.qt.trading.page.hpp b/src/atomic.dex.qt.trading.page.hpp index f2a6e05951..3cf4c678ed 100644 --- a/src/atomic.dex.qt.trading.page.hpp +++ b/src/atomic.dex.qt.trading.page.hpp @@ -92,6 +92,12 @@ namespace atomic_dex Q_INVOKABLE void cancel_order(const QString& order_id); Q_INVOKABLE void cancel_all_orders(); Q_INVOKABLE void cancel_all_orders_by_ticker(const QString& ticker); + Q_INVOKABLE QString place_buy_order( + const QString& base, const QString& rel, const QString& price, const QString& volume, bool is_created_order, const QString& price_denom, + const QString& price_numer, const QString& base_nota = "", const QString& base_confs = ""); + Q_INVOKABLE QString place_sell_order( + const QString& base, const QString& rel, const QString& price, const QString& volume, bool is_created_order, const QString& price_denom, + const QString& price_numer, const QString& rel_nota = "", const QString& rel_confs = ""); //! Properties [[nodiscard]] qt_orderbook_wrapper* get_orderbook_wrapper() const noexcept; From b72b313c37b2872519fba1a09892d28ea6a492bb Mon Sep 17 00:00:00 2001 From: romanszterg Date: Fri, 7 Aug 2020 18:37:10 +0200 Subject: [PATCH 205/515] feat(market_selector): adding market pairs selector basis --- CMakeLists.txt | 1 + src/atomic.dex.qt.market.pairs.cpp | 64 ++++++++++++++++++++++++++++++ src/atomic.dex.qt.market.pairs.hpp | 51 ++++++++++++++++++++++++ src/atomic.dex.qt.trading.page.cpp | 20 +++++++++- src/atomic.dex.qt.trading.page.hpp | 26 +++++++----- 5 files changed, 151 insertions(+), 11 deletions(-) create mode 100644 src/atomic.dex.qt.market.pairs.cpp create mode 100644 src/atomic.dex.qt.market.pairs.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 9d359d16d2..3ee50bde95 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -163,6 +163,7 @@ target_sources(atomic_qt_shared_deps INTERFACE ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.addressbook.proxy.filter.model.cpp ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.contact.model.cpp ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.trading.page.cpp + ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.market.pairs.cpp ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.orderbook.cpp ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.orderbook.model.cpp ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.orderbook.proxy.model.cpp diff --git a/src/atomic.dex.qt.market.pairs.cpp b/src/atomic.dex.qt.market.pairs.cpp new file mode 100644 index 0000000000..eb427885c4 --- /dev/null +++ b/src/atomic.dex.qt.market.pairs.cpp @@ -0,0 +1,64 @@ +/****************************************************************************** + * Copyright © 2013-2019 The Komodo Platform Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * Komodo Platform software, including this file may be copied, modified, * + * propagated or distributed except according to the terms contained in the * + * LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + +#include "atomic.dex.qt.market.pairs.hpp" + +namespace atomic_dex +{ + market_pairs::market_pairs(QObject* parent) : QObject(parent) {} + market_pairs::~market_pairs() noexcept {} +} // namespace atomic_dex + +//! Properties implementation +namespace atomic_dex +{ + QString + market_pairs::get_left_selected_coin() const noexcept + { + return m_left_selected_coin; + } + + QString + market_pairs::get_right_selected_coin() const noexcept + { + return m_right_selected_coin; + } + + void + market_pairs::set_left_selected_coin(QString left_coin) noexcept + { + if (left_coin != m_left_selected_coin) + { + m_left_selected_coin = std::move(left_coin); + emit leftSelectedCoinChanged(); + } + } + + void + market_pairs::set_right_selected_coin(QString right_coin) noexcept + { + if (right_coin != m_right_selected_coin) + { + m_right_selected_coin = std::move(right_coin); + emit rightSelectedCoinChanged(); + } + } +} // namespace atomic_dex + +//! public API +namespace atomic_dex +{ +} // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.market.pairs.hpp b/src/atomic.dex.qt.market.pairs.hpp new file mode 100644 index 0000000000..df1cfe143d --- /dev/null +++ b/src/atomic.dex.qt.market.pairs.hpp @@ -0,0 +1,51 @@ +/****************************************************************************** + * Copyright © 2013-2019 The Komodo Platform Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * Komodo Platform software, including this file may be copied, modified, * + * propagated or distributed except according to the terms contained in the * + * LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + +#pragma once + +//! QT Headers +#include + +namespace atomic_dex +{ + class market_pairs final : public QObject + { + //! Q_OBJECT Definition + Q_OBJECT + + //! QT Properties + Q_PROPERTY(QString left_selected_coin READ get_left_selected_coin WRITE set_left_selected_coin NOTIFY leftSelectedCoinChanged) + Q_PROPERTY(QString right_selected_coin READ get_right_selected_coin WRITE set_right_selected_coin NOTIFY rightSelectedCoinChanged) + + QString m_left_selected_coin{"KMD"}; + QString m_right_selected_coin{"BTC"}; + + public: + //! Constructor / Destructor + market_pairs(QObject* parent = nullptr); + ~market_pairs() noexcept final; + + //! Properties Getter/Setter + [[nodiscard]] QString get_left_selected_coin() const noexcept; + [[nodiscard]] QString get_right_selected_coin() const noexcept; + void set_left_selected_coin(QString left_coin) noexcept; + void set_right_selected_coin(QString right_coin) noexcept; + + signals: + void leftSelectedCoinChanged(); + void rightSelectedCoinChanged(); + }; +} // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.trading.page.cpp b/src/atomic.dex.qt.trading.page.cpp index cad7dc969c..5761644199 100644 --- a/src/atomic.dex.qt.trading.page.cpp +++ b/src/atomic.dex.qt.trading.page.cpp @@ -25,7 +25,9 @@ namespace atomic_dex { trading_page::trading_page(entt::registry& registry, ag::ecs::system_manager& system_manager, std::atomic_bool& exit_status, QObject* parent) : QObject(parent), system(registry), m_system_manager(system_manager), - m_about_to_exit_the_app(exit_status), m_models{{new qt_orderbook_wrapper(m_system_manager, this), new candlestick_charts_model(m_system_manager, this)}} + m_about_to_exit_the_app(exit_status), m_models{ + {new qt_orderbook_wrapper(m_system_manager, this), new candlestick_charts_model(m_system_manager, this), + new market_pairs(this)}} { //! } @@ -70,9 +72,19 @@ namespace atomic_dex auto& provider = m_system_manager.get_system(); auto [normal, quoted] = provider.is_pair_supported(base.toStdString(), rel.toStdString()); get_candlestick_charts()->set_is_pair_supported(normal || quoted); + auto* market_selector_mdl = get_market_pairs_mdl(); + market_selector_mdl->set_left_selected_coin(base); + market_selector_mdl->set_right_selected_coin(rel); dispatcher_.trigger(base.toStdString(), rel.toStdString()); } + void + trading_page::swap_market_pair() + { + auto* market_selector_mdl = get_market_pairs_mdl(); + set_current_orderbook(market_selector_mdl->get_right_selected_coin(), market_selector_mdl->get_left_selected_coin()); + } + void trading_page::on_gui_enter_dex() { @@ -254,4 +266,10 @@ namespace atomic_dex { return qobject_cast(m_models[models::ohlc]); } + + market_pairs* + trading_page::get_market_pairs_mdl() const noexcept + { + return qobject_cast(m_models[models::market_selector]); + } } // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.trading.page.hpp b/src/atomic.dex.qt.trading.page.hpp index 3cf4c678ed..33f57fa4f5 100644 --- a/src/atomic.dex.qt.trading.page.hpp +++ b/src/atomic.dex.qt.trading.page.hpp @@ -26,6 +26,7 @@ #include "atomic.dex.events.hpp" #include "atomic.dex.qt.actions.hpp" #include "atomic.dex.qt.candlestick.charts.model.hpp" +#include "atomic.dex.qt.market.pairs.hpp" #include "atomic.dex.qt.orderbook.hpp" namespace atomic_dex @@ -38,13 +39,15 @@ namespace atomic_dex //! Q Properties definitions Q_PROPERTY(qt_orderbook_wrapper* orderbook READ get_orderbook_wrapper NOTIFY orderbookChanged) Q_PROPERTY(candlestick_charts_model* candlestick_charts_mdl READ get_candlestick_charts NOTIFY candlestickChartsChanged) + Q_PROPERTY(market_pairs* market_pairs_mdl READ get_market_pairs_mdl NOTIFY marketPairsChanged) //! Private enum enum models { - orderbook = 0, - ohlc = 1, - models_size = 2 + orderbook = 0, + ohlc = 1, + market_selector = 2, + models_size = 3 }; enum models_actions @@ -86,22 +89,24 @@ namespace atomic_dex void disconnect_signals(); //! Public QML API - Q_INVOKABLE void set_current_orderbook(const QString& base, const QString& rel); - Q_INVOKABLE void on_gui_enter_dex(); - Q_INVOKABLE void on_gui_leave_dex(); - Q_INVOKABLE void cancel_order(const QString& order_id); - Q_INVOKABLE void cancel_all_orders(); - Q_INVOKABLE void cancel_all_orders_by_ticker(const QString& ticker); - Q_INVOKABLE QString place_buy_order( + Q_INVOKABLE void set_current_orderbook(const QString& base, const QString& rel); + Q_INVOKABLE void on_gui_enter_dex(); + Q_INVOKABLE void on_gui_leave_dex(); + Q_INVOKABLE void cancel_order(const QString& order_id); + Q_INVOKABLE void cancel_all_orders(); + Q_INVOKABLE void cancel_all_orders_by_ticker(const QString& ticker); + Q_INVOKABLE QString place_buy_order( const QString& base, const QString& rel, const QString& price, const QString& volume, bool is_created_order, const QString& price_denom, const QString& price_numer, const QString& base_nota = "", const QString& base_confs = ""); Q_INVOKABLE QString place_sell_order( const QString& base, const QString& rel, const QString& price, const QString& volume, bool is_created_order, const QString& price_denom, const QString& price_numer, const QString& rel_nota = "", const QString& rel_confs = ""); + Q_INVOKABLE void swap_market_pair(); //! Properties [[nodiscard]] qt_orderbook_wrapper* get_orderbook_wrapper() const noexcept; [[nodiscard]] candlestick_charts_model* get_candlestick_charts() const noexcept; + [[nodiscard]] market_pairs* get_market_pairs_mdl() const noexcept; //! Events Callbacks void on_process_orderbook_finished_event(const process_orderbook_finished& evt) noexcept; @@ -111,6 +116,7 @@ namespace atomic_dex signals: void orderbookChanged(); void candlestickChartsChanged(); + void marketPairsChanged(); }; } // namespace atomic_dex From 518a1643028900d7d59cdb7594254a89f8d1366a Mon Sep 17 00:00:00 2001 From: romanszterg Date: Fri, 7 Aug 2020 19:52:34 +0200 Subject: [PATCH 206/515] feat(trading): add portfolio proxy mdl for selection box --- .../assets/languages/atomic_qt_en.ts | 590 ++++++++++------- .../assets/languages/atomic_qt_fr.ts | 614 ++++++++++++------ .../assets/languages/atomic_qt_tr.ts | 608 +++++++++++------ src/atomic.dex.app.cpp | 6 +- src/atomic.dex.qt.market.pairs.cpp | 22 +- src/atomic.dex.qt.market.pairs.hpp | 27 +- src/atomic.dex.qt.trading.page.cpp | 8 +- src/atomic.dex.qt.trading.page.hpp | 5 +- 8 files changed, 1206 insertions(+), 674 deletions(-) diff --git a/atomic_qt_design/assets/languages/atomic_qt_en.ts b/atomic_qt_design/assets/languages/atomic_qt_en.ts index 0d854f65ea..9d28c02d8b 100644 --- a/atomic_qt_design/assets/languages/atomic_qt_en.ts +++ b/atomic_qt_design/assets/languages/atomic_qt_en.ts @@ -19,26 +19,34 @@ - + Enter the contact name - + Enter the address - + Explorer - + Send + + CandleStickChart + + + There is no chart data for this pair yet + + + ClaimRewardsModal @@ -72,27 +80,57 @@ ConfirmTradeModal - + Confirm Exchange Details - + This swap request can not be undone and is a final event! - + This transaction can take up to 10 mins - DO NOT close this application! - + + Enable Komodo dPoW security + + + + + Enable Notarization + + + + + Change required confirmations + + + + + Confirmations + + + + + Recommended + + + + + Warning, this atomic swap is not dPoW/blockchain confirmation protected + + + + Cancel - + Confirm @@ -108,22 +146,22 @@ Dashboard - + News - + Dapps - + CEX Data - + Markets data (prices, charts, etc.) marked with the ⓘ icon originates from third party sources. (<a href="https://coinpaprika.com">coinpaprika.com</a>) @@ -131,38 +169,38 @@ DeleteWalletModal - + Delete Wallet - + Are you sure you want to delete %1 wallet? WALLET_NAME - + If so, make sure you record your seed phrase in order to restore your wallet in future. - + Enter the password of your wallet - + Wrong Password - + Cancel - + Delete @@ -170,42 +208,42 @@ EnableCoinModal - + Enable coins - + Search - + Select all UTXO coins - + Select all SmartChains - + Select all ERC tokens - + All coins are already enabled! - + Close - + Enable @@ -284,45 +322,55 @@ Exchange - + Trade - + Orders - + History - + Order Matching - + Order Matched - + Swap Ongoing - + Swap Successful - + + Refunding + + + + Swap Failed + + + Unknown State + + FirstLaunch @@ -350,12 +398,12 @@ History - + Recent Swaps - + Recover Funds Result @@ -400,7 +448,7 @@ - + Login @@ -433,58 +481,58 @@ - + %1 / %2 Price TICKER - + Volume 24h - + Address Book - + Send - + Receive - + Swap - + Claim Rewards - + Loading - + Scanning blocks for TX History... - + Syncing TX History... - + No transactions @@ -497,63 +545,63 @@ - + Failed to create a wallet - + New User - + Important: Back up your seed phrase before proceeding! - + We recommend storing it offline. - + Generated Seed - + Confirm Seed - + Enter the generated seed here - + Back - - + + Continue - + Let's double check your seed phrase - + Your seed phrase is important - that's why we like to make sure it's correct. We'll ask you three different questions about your seed phrase to make sure you'll be able to easily restore your wallet whenever you want. - + What's the %n. word in your seed phrase? @@ -561,7 +609,7 @@ - + Enter the %n. word @@ -569,7 +617,7 @@ - + Go back and check again @@ -577,45 +625,50 @@ NoConnection - + No connection - + Please make sure you are connected to the internet - - - OrderContent - - Swap ID + + Will automatically retry in %1 seconds + + + + + Retry + + + OrderContent - - UUID + + ID - + Maker Order - + Taker Order - + Cancel - + Recover Funds @@ -623,68 +676,80 @@ OrderForm - + Sell - - Receive + + Amount to sell - - Amount + + Amount to receive - - Amount to sell + + Buy - - Amount to receive + + Price - - Please fill the send amount + + Volume - + Min - + Half - + Max - + Transaction Fee - + Trading Fee - + Fees will be calculated - - Trade + + Total + + + + + Sell %1 + TICKER + + + + + Buy %1 + TICKER @@ -699,186 +764,140 @@ OrderModal - + Swap Details - + Order Details - + Maker Order - + Taker Order - + Refund State - + Your swap failed but the auto-refund process for your payment started already. Please wait and keep application opened until you receive your payment back - + Date - - Swap ID - - - - - UUID - - - - + Maker Payment Sent ID - + Maker Payment Spent ID - + Taker Payment Spent ID - + Taker Payment Sent ID - + Cancel Order - + Error ID - - Error Log + + ID - - Close - - - - - View at Explorer - - - - - OrderReceiveModal - - - Receive - - - - - Search + + Error Log - - Click to create an order + + Close - - - Click to see %n order(s) - - - - - - - Close + + View at Explorer - OrderbookModal - - - Orderbook - - + OrderbookSection - - Price + + Ask Price - - Volume + + Bid Price - - Receive + + Quantity - - Close - - - - - Create your own order + + Total Orders - + Show All Coins - + Cancel All Orders - + Cancel All %1 Orders TICKER - + All %1 Orders TICKER - + All Orders @@ -996,33 +1015,38 @@ PriceLine - + + Fill the amounts to see the price information + + + + Exchange rate - + Selected - + Expensive - + Expedient - + %1 compared to CEX PRICE_DIFF% - + CEXchange rate @@ -1030,17 +1054,17 @@ ReceiveModal - + Receive - + Share this address to receive coins - + Close @@ -1048,39 +1072,39 @@ RecoverSeed - + Failed to recover the seed - + Recovery - - + + Seed - - + + Enter the seed - + Allow custom seed - + Back - + Confirm @@ -1088,37 +1112,37 @@ RecoverSeedModal - + View Seed - + Please enter your password to view the seed. - + Wrong Password - + Seed - + Cancel - + Close - + View @@ -1144,140 +1168,140 @@ SendModal - + Prepare to Send - - + + Recipient's address - + Enter address of the recipient - + Address Book - + The address has to be mixed case. - + Fix - + Amount to send - + Enter the amount to send - + MAX - + Enable Custom Fees - + Only use custom fees if you know what you are doing! - + Custom Fee - + Enter the custom fee - + Gas Limit - + Enter the gas limit - + Gas Price - + Enter the gas price - + Custom Fee can't be higher than the amount - + Not enough funds. - + You have %1 AMT TICKER - + Close - + Prepare - - + + Send - + Amount - + Fees - + Date - + Back @@ -1366,7 +1390,7 @@ Sidebar - + Disable %1 TICKER @@ -1421,6 +1445,14 @@ + + TextFieldWithTitle + + + Required + + + Toast @@ -1432,44 +1464,54 @@ Trade - + No balance available - + Please enable a coin with balance or deposit funds - + Placed the order - + Failed to place the order - + + Please fill the price field + + + + + %1 balance is lower than minimum trade amount + + + + Not enough balance for the fees. Need at least %1 more AMT TICKER - - Not enough ETH for the transaction fee + + Please fill the volume field - - Sell amount is lower than minimum trade amount + + Not enough ETH for the transaction fee - - Receive amount is lower than minimum trade amount + + Amount is lower than minimum trade amount @@ -1549,16 +1591,72 @@ - + transaction fee - + Unconfirmed + + UpdateModal + + + Available + + + + + Required + + + + + Recommended + + + + + New Update! + + + + + Problem occured + + + + + Skip + + + + + Download + + + + + UpdateNotificationLine + + + New update available! + + + + + Version: + + + + + Click here for the details. + + + WalletNameField diff --git a/atomic_qt_design/assets/languages/atomic_qt_fr.ts b/atomic_qt_design/assets/languages/atomic_qt_fr.ts index 5ba4de8418..5b2370a51e 100644 --- a/atomic_qt_design/assets/languages/atomic_qt_fr.ts +++ b/atomic_qt_design/assets/languages/atomic_qt_fr.ts @@ -19,22 +19,22 @@ - + Enter the contact name - + Enter the address - + Explorer - + Send Envoyez @@ -46,6 +46,14 @@ version de la gui + + CandleStickChart + + + There is no chart data for this pair yet + + + ClaimRewardsModal @@ -79,27 +87,57 @@ ConfirmTradeModal - + Confirm Exchange Details Détails de la confirmation de l'échange - + This swap request can not be undone and is a final event! La requête de ce swap ne peut pas être annulé, c'est irréversible ! - + This transaction can take up to 10 mins - DO NOT close this application! Cette transaction peut prendre jusqu'à 10 mins - NE fermez pas l'application ! - + + Enable Komodo dPoW security + + + + + Enable Notarization + + + + + Change required confirmations + + + + + Confirmations + Confirmations + + + + Recommended + + + + + Warning, this atomic swap is not dPoW/blockchain confirmation protected + + + + Cancel Annuler - + Confirm Confirmer @@ -115,22 +153,22 @@ Dashboard - + News Actualités - + Dapps - + CEX Data - + Markets data (prices, charts, etc.) marked with the ⓘ icon originates from third party sources. (<a href="https://coinpaprika.com">coinpaprika.com</a>) @@ -142,38 +180,38 @@ DeleteWalletModal - + Delete Wallet Supprimez votre portefeuille - + Are you sure you want to delete %1 wallet? WALLET_NAME Êtes-vous sûre de supprimez le portefeuille %1 ? - + If so, make sure you record your seed phrase in order to restore your wallet in future. Si c'est le cas, faite en sorte que votre phrase de récupération soit sauvegardée pour pouvoir restaurer votre portefeuille à l'avenir. - + Enter the password of your wallet Entrez le mot de passe de votre portefeuille - + Wrong Password Mauvais mot de passe - + Cancel Annuler - + Delete Supprimez @@ -181,42 +219,42 @@ EnableCoinModal - + Enable coins Activer les pièces - + Search Rechercher - + Select all UTXO coins Selectionnez toutes les pièces UTXO - + Select all SmartChains Selectionnez toutes les SmartChains - + Select all ERC tokens Selectionnez tous les jetons ERC - + All coins are already enabled! Toutes les pièces sont déjà activées ! - + Close Fermer - + Enable Activer @@ -295,45 +333,55 @@ Exchange - + Trade Échanger - + Orders Ordres - + History Historique - + Order Matching Recherche d'un ordre - + Order Matched Ordre trouvé - + Swap Ongoing Échange en cours - + Swap Successful Échange terminé - + + Refunding + + + + Swap Failed Erreur lors de l'échange + + + Unknown State + + FirstLaunch @@ -365,12 +413,12 @@ History - + Recent Swaps Swaps récents - + Recover Funds Result Le résultat de la récupération des fonds @@ -415,7 +463,7 @@ - + Login Connection @@ -448,58 +496,58 @@ - + %1 / %2 Price TICKER - + Volume 24h - + Address Book - + Send Envoyez - + Receive Recevoir - + Swap Échange - + Claim Rewards Réclamer des récompenses - + Loading Chargement - + Scanning blocks for TX History... - + Syncing TX History... - + No transactions Pas de transactions @@ -512,63 +560,63 @@ Mauvais mot, veuillez vérifier à nouveau - + Failed to create a wallet Impossible de créer un portefeuille - + New User Nouvel utilisateur - + Important: Back up your seed phrase before proceeding! Important: sauvegardez votre phrase de recupération avant de continuer ! - + We recommend storing it offline. Nous vous recommandons de le stocker hors ligne. - + Generated Seed Générer un Seed - + Confirm Seed Confirmer la phrase de récupération - + Enter the generated seed here Veuillez entrez la phrase de récupération ici - + Back Retour - - + + Continue Continuer - + Let's double check your seed phrase Vérifions à nouveau votre phrase de récupération - + Your seed phrase is important - that's why we like to make sure it's correct. We'll ask you three different questions about your seed phrase to make sure you'll be able to easily restore your wallet whenever you want. Votre phrase de récupération est importante - c'est pourquoi nous aimons nous assurer qu'elle est correcte. Nous vous poserons trois questions différentes au sujet de votre phrase source pour vous assurer que vous pourrez facilement restaurer votre portefeuille à tout moment. - + What's the %n. word in your seed phrase? Quel est le mot numéro %n dans votre phrase de récupération ? @@ -576,7 +624,7 @@ - + Enter the %n. word Entrez le mot numéro %n @@ -584,7 +632,7 @@ - + Go back and check again Revenez en arrière et vérifiez à nouveau @@ -596,45 +644,69 @@ NoConnection - + No connection Pas de connéction - + Please make sure you are connected to the internet Veuillez vous assurer que vous êtes connecté à Internet + + + Will automatically retry in %1 seconds + + + + + Retry + + + + + NotificationsPanel + + AtomicDEX Pro + AtomicDEX Pro + + + Close + Fermer + OrderContent - Swap ID - Identifiant du Swap + Identifiant du Swap - UUID - UUID + UUID + + + + ID + - + Maker Order Ordre de vente - + Taker Order Ordre d'achat - + Cancel Annuler - + Recover Funds Récupérer des fonds @@ -642,73 +714,101 @@ OrderForm - + Sell Vendre - Receive - Recevoir + Recevoir MAX MAX - Amount - Montant + Montant - + Amount to sell Montant à vendre - + Amount to receive Montant à recevoir - Please fill the send amount - Veuillez remplir le montant de la vente + Veuillez remplir le montant de la vente + + + + Buy + - + + Price + Prix + + + + Volume + Volume + + + Min - + Half - + Max - + Transaction Fee Frais de transactions - + Trading Fee Frais d'échanges - + Fees will be calculated - + + Total + + + + + Sell %1 + TICKER + + + + + Buy %1 + TICKER + + + Trade - Échanger + Échanger @@ -745,72 +845,75 @@ OrderModal - + Swap Details Détails de l'échange - + Order Details Détails de l'ordre - + Maker Order Ordre de vente - + Taker Order Ordre d'achat - + Refund State - + Your swap failed but the auto-refund process for your payment started already. Please wait and keep application opened until you receive your payment back - + Date Date - + + ID + + + Swap ID - Identifiant du Swap + Identifiant du Swap - UUID - UUID + UUID - + Maker Payment Sent ID - + Maker Payment Spent ID - + Taker Payment Spent ID - + Taker Payment Sent ID - + Cancel Order @@ -823,17 +926,17 @@ ID du paiement du vendeur - + Error ID ID de l'erreur - + Error Log Journal des erreurs - + Close Fermer @@ -842,7 +945,7 @@ Annuler - + View at Explorer Voir dans l'explorateur @@ -850,93 +953,105 @@ OrderReceiveModal - Receive - Recevoir + Recevoir - Search - Rechercher + Rechercher - Click to create an order - Cliquez pour créer un ordre + Cliquez pour créer un ordre - Click to see %n order(s) - + Cliquez pour voir %n ordre (s) Cliquez pour voir %n ordre (s) - Close - Fermer + Fermer OrderbookModal - Orderbook - Carnet d'ordres + Carnet d'ordres - Price - Prix + Prix - Volume - Volume + Volume - Receive - Recevoir + Recevoir - Close - Fermer + Fermer - Create your own order - Créez votre propre ordre + Créez votre propre ordre + + + + OrderbookSection + + + Ask Price + + + + + Bid Price + + + + + Quantity + + + + + Total + Orders - + Show All Coins - + Cancel All Orders Annuler tous les ordres - + Cancel All %1 Orders TICKER - + All %1 Orders TICKER Tous les ordres %1 - + All Orders @@ -1062,33 +1177,38 @@ Prix ​​sélectionné - + + Fill the amounts to see the price information + + + + Exchange rate - + Selected - + Expensive - + Expedient - + %1 compared to CEX PRICE_DIFF% - + CEXchange rate @@ -1096,17 +1216,17 @@ ReceiveModal - + Receive Recevoir - + Share this address to receive coins Partagez cette adresse pour recevoir des pièces - + Close Fermer @@ -1114,39 +1234,39 @@ RecoverSeed - + Failed to recover the seed Impossible de récupérer la phrase de récupération - + Recovery Récupération - - + + Seed Phrase de récupération - - + + Enter the seed Entrez la phrase de récupération - + Allow custom seed Autoriser les phrases de récupération personnalisées - + Back Retour - + Confirm Confirmer @@ -1154,37 +1274,37 @@ RecoverSeedModal - + View Seed Voir la phrase de récupération - + Please enter your password to view the seed. Veuillez entrer votre mot de passe pour voir la phrase de récupération. - + Wrong Password Mauvais mot de passe - + Seed Phrase de récupération - + Cancel Annuler - + Close Fermer - + View Voir @@ -1210,140 +1330,140 @@ SendModal - + Prepare to Send Préparez-pour l'envoie - - + + Recipient's address Adresse du destinataire - + Enter address of the recipient Entrez l'adresse du destinataire - + Address Book - + The address has to be mixed case. L'adresse doit être mixte (case). - + Fix Réparer - + Amount to send Montant à envoyer - + Enter the amount to send Entrez le montant à envoyer - + MAX MAX - + Enable Custom Fees Activer les frais personnalisés - + Only use custom fees if you know what you are doing! N'utilisez des frais personnalisés que si vous savez ce que vous faites ! - + Custom Fee Frais personnalisés - + Enter the custom fee Entrez les frais personnalisées - + Gas Limit Limite de gaz - + Enter the gas limit Entrez la limite de gaz - + Gas Price Prix ​​du gaz - + Enter the gas price Entrez le prix du gaz - + Custom Fee can't be higher than the amount Les frais personnalisées ne peuvent pas être supérieurs au montant - + Not enough funds. Pas assez de fonds. - + You have %1 AMT TICKER Vous avez %1 - + Close Fermer - + Prepare Préparer - - + + Send Envoyez - + Amount Montant - + Fees Frais - + Date Date - + Back Retour @@ -1460,7 +1580,7 @@ Réglages - + Disable %1 TICKER @@ -1515,6 +1635,14 @@ Vous n'avez pas d'ordres récents. + + TextFieldWithTitle + + + Required + + + Toast @@ -1526,12 +1654,12 @@ Trade - + No balance available Aucun solde disponible - + Please enable a coin with balance or deposit funds Veuillez activer une pièce avec solde ou déposez des fonds @@ -1544,35 +1672,53 @@ Impossible de placer l'ordre. - + Placed the order - + Failed to place the order - + + Please fill the price field + + + + + %1 balance is lower than minimum trade amount + + + + Not enough balance for the fees. Need at least %1 more AMT TICKER - + + Please fill the volume field + + + + Not enough ETH for the transaction fee Pas assez d'ETH pour les frais de transaction - + + Amount is lower than minimum trade amount + + + Sell amount is lower than minimum trade amount - Le montant de la vente est inférieur au montant minimum de l'échange + Le montant de la vente est inférieur au montant minimum de l'échange - Receive amount is lower than minimum trade amount - Le montant reçu est inférieur au montant minimum de l'échange + Le montant reçu est inférieur au montant minimum de l'échange @@ -1651,16 +1797,72 @@ - + transaction fee - + Unconfirmed + + UpdateModal + + + Available + + + + + Required + + + + + Recommended + + + + + New Update! + + + + + Problem occured + + + + + Skip + + + + + Download + + + + + UpdateNotificationLine + + + New update available! + + + + + Version: + + + + + Click here for the details. + + + Wallet diff --git a/atomic_qt_design/assets/languages/atomic_qt_tr.ts b/atomic_qt_design/assets/languages/atomic_qt_tr.ts index cb97a4d07d..c8439ea929 100644 --- a/atomic_qt_design/assets/languages/atomic_qt_tr.ts +++ b/atomic_qt_design/assets/languages/atomic_qt_tr.ts @@ -19,22 +19,22 @@ - + Enter the contact name - + Enter the address - + Explorer - + Send Gönder @@ -50,6 +50,14 @@ gui versiyonu + + CandleStickChart + + + There is no chart data for this pair yet + + + ClaimRewardsModal @@ -83,27 +91,57 @@ ConfirmTradeModal - + Confirm Exchange Details Al-Sat Detaylarını Onayla - + This swap request can not be undone and is a final event! Bu takas isteği geri döndürülemez! - + This transaction can take up to 10 mins - DO NOT close this application! Bu işlem 10 dakika kadar sürebilir - Programı KAPATMAYINIZ! - + + Enable Komodo dPoW security + + + + + Enable Notarization + + + + + Change required confirmations + + + + + Confirmations + Onay Sayısı + + + + Recommended + + + + + Warning, this atomic swap is not dPoW/blockchain confirmation protected + + + + Cancel İptal - + Confirm Onayla @@ -119,22 +157,22 @@ Dashboard - + News Haberler - + Dapps - + CEX Data - + Markets data (prices, charts, etc.) marked with the ⓘ icon originates from third party sources. (<a href="https://coinpaprika.com">coinpaprika.com</a>) @@ -146,38 +184,38 @@ DeleteWalletModal - + Delete Wallet Cüzdanı Sil - + Are you sure you want to delete %1 wallet? WALLET_NAME %1 cüzdanınızı silmek istediğinizden emin misiniz? - + If so, make sure you record your seed phrase in order to restore your wallet in future. Öyleyse, cüzdanınızı gelecekte kurtarabilmeniz için seed satırınızı kaydettiğinizden emin olunuz. - + Enter the password of your wallet Cüzdanınızın şifresini giriniz - + Wrong Password Yanlış Parola - + Cancel İptal - + Delete Sil @@ -185,42 +223,42 @@ EnableCoinModal - + Enable coins Kriptopara etkinleştir - + Search Ara - + Select all UTXO coins Tüm UTXO kriptoparaları seç - + Select all SmartChains Tüm SmartChain'leri seç - + Select all ERC tokens Tüm ERC tokenlarını seç - + All coins are already enabled! Tüm kriptoparalar zaten etkin! - + Close Kapat - + Enable Etkinleştir @@ -299,45 +337,55 @@ Exchange - + Trade Al-Sat - + Orders Emirler - + History Geçmiş - + Order Matching Emir Eşleşiyor - + Order Matched Emir Eşleşti - + Swap Ongoing Takas Devam Ediyor - + Swap Successful Takas Başarılı - + + Refunding + + + + Swap Failed Takas Başarısız + + + Unknown State + + FirstLaunch @@ -369,12 +417,12 @@ History - + Recent Swaps Son Takaslar - + Recover Funds Result @@ -419,7 +467,7 @@ - + Login Giriş @@ -452,58 +500,58 @@ - + %1 / %2 Price TICKER - + Volume 24h - + Address Book - + Send Gönder - + Receive - + Swap Takasla - + Claim Rewards Ödül Al - + Loading Yükleniyor - + Scanning blocks for TX History... - + Syncing TX History... - + No transactions İşlem yok @@ -516,77 +564,77 @@ Hatalı kelime, lütfen kontrol ediniz - + Failed to create a wallet Cüzdan oluşturulamadı - + New User Yeni Kullanıcı - + Important: Back up your seed phrase before proceeding! Önemli: Devam etmeden önce seed kelimelerinizi yedekleyin! - + We recommend storing it offline. Çevrimdışı saklamanızı öneririz. - + Generated Seed Seed Oluştur - + Confirm Seed Seed'i Onayla - + Enter the generated seed here Oluşturulmuş Seed'i buraya giriniz - + Back Geri - - + + Continue Devam - + Let's double check your seed phrase Seed kelimelerinizi tekrar kontrol edelim - + Your seed phrase is important - that's why we like to make sure it's correct. We'll ask you three different questions about your seed phrase to make sure you'll be able to easily restore your wallet whenever you want. Seed kelimeleriniz önemlidir - bu yüzden doğru olduğundan emin olmak istiyoruz. Cüzdanınızı istediğiniz zaman kolayca kurtarabileceğinizden emin olmak için seed kelimeleriniz hakkında üç farklı soru soracağız. - + What's the %n. word in your seed phrase? Seed kelimelerinizden %n. kelime nedir? - + Enter the %n. word %n. kelimeyi giriniz - + Go back and check again Geri dönüp tekrar kontrol et @@ -598,45 +646,69 @@ NoConnection - + No connection Bağlantı yok - + Please make sure you are connected to the internet Lütfen internete bağlı olduğunuzdan emin olun + + + Will automatically retry in %1 seconds + + + + + Retry + + + + + NotificationsPanel + + AtomicDEX Pro + AtomıcDEX Pro + + + Close + Kapat + OrderContent - Swap ID - Takas ID + Takas ID - UUID - UUID + UUID - + + ID + + + + Maker Order Yapıcı Emir - + Taker Order Alıcı Emir - + Cancel İptal - + Recover Funds @@ -644,73 +716,101 @@ OrderForm - + Sell Satılacak - Receive - Alınacak + Alınacak MAX MAKS - Amount - Miktar + Miktar - + Amount to sell Satılacak miktar - + Amount to receive Alınacak miktar - Please fill the send amount - Lütfen gönderilecek miktarı giriniz + Lütfen gönderilecek miktarı giriniz + + + + Buy + - + + Price + Fiyat + + + + Volume + Hacim + + + Min - + Half - + Max - + Transaction Fee İşlem Ücreti - + Trading Fee Al-Sat Ücreti - + Fees will be calculated - + + Total + + + + + Sell %1 + TICKER + + + + + Buy %1 + TICKER + + + Trade - Al-Sat + Al-Sat @@ -747,72 +847,75 @@ OrderModal - + Swap Details Takas Detayları - + Order Details Emir Detayları - + Maker Order Satıcı Emri - + Taker Order Alıcı Emri - + Refund State - + Your swap failed but the auto-refund process for your payment started already. Please wait and keep application opened until you receive your payment back - + Date Tarih - + + ID + + + Swap ID - Takas ID + Takas ID - UUID - UUID + UUID - + Maker Payment Sent ID - + Maker Payment Spent ID - + Taker Payment Spent ID - + Taker Payment Sent ID - + Cancel Order @@ -825,17 +928,17 @@ Alıcı Ödeme ID - + Error ID Hata ID - + Error Log Hata Kaydı - + Close Kapat @@ -844,7 +947,7 @@ İptal - + View at Explorer Explorer'da Görüntüle @@ -852,92 +955,104 @@ OrderReceiveModal - Receive - Al + Al - Search - Ara + Ara - Click to create an order - Emir oluşturmak için tıkla + Emir oluşturmak için tıkla - Click to see %n order(s) - + %n emri görüntüle - Close - Kapat + Kapat OrderbookModal - Orderbook - Emir Defteri + Emir Defteri - Price - Fiyat + Fiyat - Volume - Hacim + Hacim - Receive - Alınacak + Alınacak - Close - Kapat + Kapat - Create your own order - Kendi emrini oluştur + Kendi emrini oluştur + + + + OrderbookSection + + + Ask Price + + + + + Bid Price + + + + + Quantity + + + + + Total + Orders - + Show All Coins - + Cancel All Orders Tüm Emirleri İptal Et - + Cancel All %1 Orders TICKER - + All %1 Orders TICKER Tüm %1 Emirleri - + All Orders @@ -1063,33 +1178,38 @@ Seçilen Fiyat - + + Fill the amounts to see the price information + + + + Exchange rate - + Selected - + Expensive - + Expedient - + %1 compared to CEX PRICE_DIFF% - + CEXchange rate @@ -1097,17 +1217,17 @@ ReceiveModal - + Receive Al - + Share this address to receive coins Kriptopara almak için bu adresi paylaşın - + Close Kapat @@ -1115,39 +1235,39 @@ RecoverSeed - + Failed to recover the seed Seed kurtarılamadı - + Recovery Kurtarma - - + + Seed Seed - - + + Enter the seed Seed'i giriniz - + Allow custom seed - + Back Geri - + Confirm Onayla @@ -1155,37 +1275,37 @@ RecoverSeedModal - + View Seed Seed'i Gör - + Please enter your password to view the seed. Seed'i görmek için lütfen parolanızı giriniz. - + Wrong Password Yanlış Parola - + Seed Seed - + Cancel İptal - + Close Kapat - + View Gör @@ -1211,140 +1331,140 @@ SendModal - + Prepare to Send Gönderi Hazırlığı - - + + Recipient's address Alıcı adresi - + Enter address of the recipient Alıcının adresini giriniz - + Address Book - + The address has to be mixed case. - + Fix - + Amount to send Gönderilecek miktar - + Enter the amount to send Gönderilecek miktarı giriniz - + MAX MAKS - + Enable Custom Fees Özel Ücretleri Etkinleştir - + Only use custom fees if you know what you are doing! Özel ücretler hakkında bilginiz yoksa kullanmayınız! - + Custom Fee Özel Ücret - + Enter the custom fee Özel ücreti giriniz - + Gas Limit Gas Limiti - + Enter the gas limit Gas limitini giriniz - + Gas Price Gas Fiyatı - + Enter the gas price Gas fiyatını giriniz - + Custom Fee can't be higher than the amount Özel Ücret miktardan daha yüksek olamaz - + Not enough funds. Yetersiz bakiye. - + You have %1 AMT TICKER %1'niz var - + Close Kapat - + Prepare Hazırla - - + + Send Gönder - + Amount Miktar - + Fees Ücret - + Date Tarih - + Back Geri @@ -1465,7 +1585,7 @@ Ayarlar - + Disable %1 TICKER %1'i Etkinsizleştir @@ -1520,6 +1640,14 @@ Yakın zamanda bir emriniz yok. + + TextFieldWithTitle + + + Required + + + Toast @@ -1531,12 +1659,12 @@ Trade - + No balance available Bakiye yok - + Please enable a coin with balance or deposit funds Lütfen bakiyeniz bulunan bir kriptopara etkinleştirin ya da mevcut bakiyenizi doldurun @@ -1545,34 +1673,44 @@ Al-Sat - + Placed the order - + Failed to place the order - + + Please fill the price field + + + + + %1 balance is lower than minimum trade amount + + + + Not enough balance for the fees. Need at least %1 more AMT TICKER - - Not enough ETH for the transaction fee + + Please fill the volume field - - Sell amount is lower than minimum trade amount + + Not enough ETH for the transaction fee - - Receive amount is lower than minimum trade amount + + Amount is lower than minimum trade amount @@ -1664,16 +1802,72 @@ - + transaction fee - + Unconfirmed + + UpdateModal + + + Available + + + + + Required + + + + + Recommended + + + + + New Update! + + + + + Problem occured + + + + + Skip + + + + + Download + + + + + UpdateNotificationLine + + + New update available! + + + + + Version: + + + + + Click here for the details. + + + Wallet diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index eb4b74e36f..f9215e8234 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -200,7 +200,7 @@ namespace atomic_dex auto& mm2_s = system_manager_.create_system(); system_manager_.create_system(mm2_s, m_config); system_manager_.create_system(mm2_s); - system_manager_.create_system(system_manager_, m_event_actions.at(events_action::about_to_exit_app), this); + system_manager_.create_system(system_manager_, m_event_actions.at(events_action::about_to_exit_app), get_portfolio(), this); connect_signals(); @@ -309,7 +309,7 @@ namespace atomic_dex void application::refresh_transactions(const mm2& mm2) { - const auto ticker = m_coin_info->get_ticker().toStdString(); + const auto ticker = m_coin_info->get_ticker().toStdString(); std::error_code ec; auto txs = mm2.get_tx_history(ticker, ec); if (!ec) @@ -388,7 +388,7 @@ namespace atomic_dex system_manager_.create_system(mm2_system, m_config); system_manager_.create_system(mm2_system); system_manager_.create_system(); - system_manager_.create_system(system_manager_, m_event_actions.at(events_action::about_to_exit_app), this); + system_manager_.create_system(system_manager_, m_event_actions.at(events_action::about_to_exit_app), get_portfolio(), this); connect_signals(); if (is_there_a_default_wallet()) diff --git a/src/atomic.dex.qt.market.pairs.cpp b/src/atomic.dex.qt.market.pairs.cpp index eb427885c4..ee30938ff1 100644 --- a/src/atomic.dex.qt.market.pairs.cpp +++ b/src/atomic.dex.qt.market.pairs.cpp @@ -18,7 +18,17 @@ namespace atomic_dex { - market_pairs::market_pairs(QObject* parent) : QObject(parent) {} + market_pairs::market_pairs(portfolio_model* portfolio_mdl, QObject* parent) : + QObject(parent), m_left_selection_box(new portfolio_proxy_model(portfolio_mdl)), m_right_selection_box(new portfolio_proxy_model(portfolio_mdl)) + { + m_left_selection_box->setSourceModel(portfolio_mdl); + m_left_selection_box->setDynamicSortFilter(true); + m_left_selection_box->sort_by_currency_balance(false); + + m_right_selection_box->setSourceModel(portfolio_mdl); + m_right_selection_box->setDynamicSortFilter(true); + m_right_selection_box->sort_by_currency_balance(false); + } market_pairs::~market_pairs() noexcept {} } // namespace atomic_dex @@ -56,6 +66,16 @@ namespace atomic_dex emit rightSelectedCoinChanged(); } } + + portfolio_proxy_model* market_pairs::get_left_selection_box() const noexcept + { + return m_left_selection_box; + } + + portfolio_proxy_model* market_pairs::get_right_selection_box() const noexcept + { + return m_right_selection_box; + } } // namespace atomic_dex //! public API diff --git a/src/atomic.dex.qt.market.pairs.hpp b/src/atomic.dex.qt.market.pairs.hpp index df1cfe143d..0be87707b6 100644 --- a/src/atomic.dex.qt.market.pairs.hpp +++ b/src/atomic.dex.qt.market.pairs.hpp @@ -19,6 +19,10 @@ //! QT Headers #include +//! Portfolio +#include "atomic.dex.qt.portfolio.model.hpp" +#include "atomic.dex.qt.portfolio.proxy.filter.model.hpp" + namespace atomic_dex { class market_pairs final : public QObject @@ -29,23 +33,32 @@ namespace atomic_dex //! QT Properties Q_PROPERTY(QString left_selected_coin READ get_left_selected_coin WRITE set_left_selected_coin NOTIFY leftSelectedCoinChanged) Q_PROPERTY(QString right_selected_coin READ get_right_selected_coin WRITE set_right_selected_coin NOTIFY rightSelectedCoinChanged) + Q_PROPERTY(portfolio_proxy_model* left_selection_box READ get_left_selection_box NOTIFY leftSelectionBoxChanged) + Q_PROPERTY(portfolio_proxy_model* right_selection_box READ get_right_selection_box NOTIFY rightSelectionBoxChanged) + + QString m_left_selected_coin{"KMD"}; + QString m_right_selected_coin{"BTC"}; + portfolio_proxy_model* m_left_selection_box; + portfolio_proxy_model* m_right_selection_box; - QString m_left_selected_coin{"KMD"}; - QString m_right_selected_coin{"BTC"}; public: //! Constructor / Destructor - market_pairs(QObject* parent = nullptr); + market_pairs(portfolio_model* portfolio_mdl, QObject* parent = nullptr); ~market_pairs() noexcept final; //! Properties Getter/Setter - [[nodiscard]] QString get_left_selected_coin() const noexcept; - [[nodiscard]] QString get_right_selected_coin() const noexcept; - void set_left_selected_coin(QString left_coin) noexcept; - void set_right_selected_coin(QString right_coin) noexcept; + [[nodiscard]] QString get_left_selected_coin() const noexcept; + [[nodiscard]] QString get_right_selected_coin() const noexcept; + [[nodiscard]] portfolio_proxy_model* get_left_selection_box() const noexcept; + [[nodiscard]] portfolio_proxy_model* get_right_selection_box() const noexcept; + void set_left_selected_coin(QString left_coin) noexcept; + void set_right_selected_coin(QString right_coin) noexcept; signals: void leftSelectedCoinChanged(); void rightSelectedCoinChanged(); + void leftSelectionBoxChanged(); + void rightSelectionBoxChanged(); }; } // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.trading.page.cpp b/src/atomic.dex.qt.trading.page.cpp index 5761644199..a4fa26a117 100644 --- a/src/atomic.dex.qt.trading.page.cpp +++ b/src/atomic.dex.qt.trading.page.cpp @@ -23,11 +23,13 @@ //! Consttructor / Destructor namespace atomic_dex { - trading_page::trading_page(entt::registry& registry, ag::ecs::system_manager& system_manager, std::atomic_bool& exit_status, QObject* parent) : - QObject(parent), system(registry), m_system_manager(system_manager), + trading_page::trading_page( + entt::registry& registry, ag::ecs::system_manager& system_manager, std::atomic_bool& exit_status, portfolio_model* portfolio, QObject* parent) : + QObject(parent), + system(registry), m_system_manager(system_manager), m_about_to_exit_the_app(exit_status), m_models{ {new qt_orderbook_wrapper(m_system_manager, this), new candlestick_charts_model(m_system_manager, this), - new market_pairs(this)}} + new market_pairs(portfolio, this)}} { //! } diff --git a/src/atomic.dex.qt.trading.page.hpp b/src/atomic.dex.qt.trading.page.hpp index 33f57fa4f5..1fecca5b68 100644 --- a/src/atomic.dex.qt.trading.page.hpp +++ b/src/atomic.dex.qt.trading.page.hpp @@ -28,6 +28,7 @@ #include "atomic.dex.qt.candlestick.charts.model.hpp" #include "atomic.dex.qt.market.pairs.hpp" #include "atomic.dex.qt.orderbook.hpp" +#include "atomic.dex.qt.portfolio.model.hpp" namespace atomic_dex { @@ -77,7 +78,9 @@ namespace atomic_dex public: //! Constructor - explicit trading_page(entt::registry& registry, ag::ecs::system_manager& system_manager, std::atomic_bool& exit_status, QObject* parent = nullptr); + explicit trading_page( + entt::registry& registry, ag::ecs::system_manager& system_manager, std::atomic_bool& exit_status, portfolio_model* portfolio, + QObject* parent = nullptr); ~trading_page() noexcept final = default; //! Public override From 4bc00a1fc5531872573eb5f2455b6e50479e6dc5 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Fri, 7 Aug 2020 20:44:12 +0200 Subject: [PATCH 207/515] feat(trading): add exclusion for market --- src/atomic.dex.qt.market.pairs.cpp | 10 ++++++++++ src/atomic.dex.qt.market.pairs.hpp | 4 ++-- src/atomic.dex.qt.portfolio.data.hpp | 2 ++ src/atomic.dex.qt.portfolio.model.cpp | 8 +++++++- src/atomic.dex.qt.portfolio.model.hpp | 3 ++- ...atomic.dex.qt.portfolio.proxy.filter.model.cpp | 15 +++++++++++++++ ...atomic.dex.qt.portfolio.proxy.filter.model.hpp | 1 + 7 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/atomic.dex.qt.market.pairs.cpp b/src/atomic.dex.qt.market.pairs.cpp index ee30938ff1..1b1ddafa96 100644 --- a/src/atomic.dex.qt.market.pairs.cpp +++ b/src/atomic.dex.qt.market.pairs.cpp @@ -21,11 +21,15 @@ namespace atomic_dex market_pairs::market_pairs(portfolio_model* portfolio_mdl, QObject* parent) : QObject(parent), m_left_selection_box(new portfolio_proxy_model(portfolio_mdl)), m_right_selection_box(new portfolio_proxy_model(portfolio_mdl)) { + //set_left_selected_coin("KMD"); m_left_selection_box->setSourceModel(portfolio_mdl); + m_left_selection_box->setFilterRole(portfolio_model::Excluded); m_left_selection_box->setDynamicSortFilter(true); m_left_selection_box->sort_by_currency_balance(false); + //set_right_selected_coin("BTC"); m_right_selection_box->setSourceModel(portfolio_mdl); + m_right_selection_box->setFilterRole(portfolio_model::Excluded); m_right_selection_box->setDynamicSortFilter(true); m_right_selection_box->sort_by_currency_balance(false); } @@ -53,6 +57,9 @@ namespace atomic_dex if (left_coin != m_left_selected_coin) { m_left_selected_coin = std::move(left_coin); + auto res_left = m_left_selection_box->match(m_left_selection_box->index(0, 0), portfolio_model::PortfolioRoles::TickerRole, m_left_selected_coin); + assert(not res_left.empty()); + m_left_selection_box->setData(res_left.at(0), portfolio_model::PortfolioRoles::Excluded, true); emit leftSelectedCoinChanged(); } } @@ -63,6 +70,9 @@ namespace atomic_dex if (right_coin != m_right_selected_coin) { m_right_selected_coin = std::move(right_coin); + auto res_right = m_right_selection_box->match(m_right_selection_box->index(0, 0), portfolio_model::PortfolioRoles::TickerRole, m_right_selected_coin); + assert(not res_right.empty()); + m_right_selection_box->setData(res_right.at(0), portfolio_model::PortfolioRoles::Excluded, true); emit rightSelectedCoinChanged(); } } diff --git a/src/atomic.dex.qt.market.pairs.hpp b/src/atomic.dex.qt.market.pairs.hpp index 0be87707b6..88ec8bbbad 100644 --- a/src/atomic.dex.qt.market.pairs.hpp +++ b/src/atomic.dex.qt.market.pairs.hpp @@ -36,8 +36,8 @@ namespace atomic_dex Q_PROPERTY(portfolio_proxy_model* left_selection_box READ get_left_selection_box NOTIFY leftSelectionBoxChanged) Q_PROPERTY(portfolio_proxy_model* right_selection_box READ get_right_selection_box NOTIFY rightSelectionBoxChanged) - QString m_left_selected_coin{"KMD"}; - QString m_right_selected_coin{"BTC"}; + QString m_left_selected_coin; + QString m_right_selected_coin; portfolio_proxy_model* m_left_selection_box; portfolio_proxy_model* m_right_selection_box; diff --git a/src/atomic.dex.qt.portfolio.data.hpp b/src/atomic.dex.qt.portfolio.data.hpp index efb7873954..31e40a3049 100644 --- a/src/atomic.dex.qt.portfolio.data.hpp +++ b/src/atomic.dex.qt.portfolio.data.hpp @@ -43,5 +43,7 @@ namespace atomic_dex //! Paprika data rates QJsonArray trend_7d; + + bool is_excluded{false}; }; } // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.portfolio.model.cpp b/src/atomic.dex.qt.portfolio.model.cpp index a2a378b9dc..b8e9d2267a 100644 --- a/src/atomic.dex.qt.portfolio.model.cpp +++ b/src/atomic.dex.qt.portfolio.model.cpp @@ -153,6 +153,8 @@ namespace atomic_dex return item.name; case Trend7D: return item.trend_7d; + case Excluded: + return item.is_excluded; } return {}; } @@ -183,6 +185,9 @@ namespace atomic_dex case Trend7D: item.trend_7d = value.toJsonArray(); break; + case Excluded: + item.is_excluded = value.toBool(); + break; default: return false; } @@ -230,7 +235,8 @@ namespace atomic_dex return {{TickerRole, "ticker"}, {NameRole, "name"}, {BalanceRole, "balance"}, {MainCurrencyBalanceRole, "main_currency_balance"}, {Change24H, "change_24h"}, {MainCurrencyPriceForOneUnit, "main_currency_price_for_one_unit"}, - {Trend7D, "trend_7d"}}; + {Trend7D, "trend_7d"}, + {Excluded, "excluded"}}; } portfolio_proxy_model* diff --git a/src/atomic.dex.qt.portfolio.model.hpp b/src/atomic.dex.qt.portfolio.model.hpp index d889fece03..2e7b07873b 100644 --- a/src/atomic.dex.qt.portfolio.model.hpp +++ b/src/atomic.dex.qt.portfolio.model.hpp @@ -47,7 +47,8 @@ namespace atomic_dex MainCurrencyBalanceRole, Change24H, MainCurrencyPriceForOneUnit, - Trend7D + Trend7D, + Excluded }; private: diff --git a/src/atomic.dex.qt.portfolio.proxy.filter.model.cpp b/src/atomic.dex.qt.portfolio.proxy.filter.model.cpp index 048f948a2c..428f2e3a2c 100644 --- a/src/atomic.dex.qt.portfolio.proxy.filter.model.cpp +++ b/src/atomic.dex.qt.portfolio.proxy.filter.model.cpp @@ -90,6 +90,21 @@ namespace atomic_dex return left_data.toString() < right_data.toString(); case portfolio_model::Trend7D: return false; + case portfolio_model::Excluded: + return false; + } + } + + bool + portfolio_proxy_model::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const + { + QModelIndex idx = this->sourceModel()->index(source_row, 0, source_parent); + assert(this->sourceModel()->hasIndex(idx.row(), 0)); + bool is_excluded = this->sourceModel()->data(idx, this->filterRole()).toBool(); + if (is_excluded) + { + return false; } + return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent); } } // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.portfolio.proxy.filter.model.hpp b/src/atomic.dex.qt.portfolio.proxy.filter.model.hpp index 689f079fa9..f86bf1668b 100644 --- a/src/atomic.dex.qt.portfolio.proxy.filter.model.hpp +++ b/src/atomic.dex.qt.portfolio.proxy.filter.model.hpp @@ -40,5 +40,6 @@ namespace atomic_dex protected: //! Override member functions [[nodiscard]] bool lessThan(const QModelIndex& source_left, const QModelIndex& source_right) const final; + bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override; }; } // namespace atomic_dex \ No newline at end of file From 4db999f5f9821dc58eef874ded2aa08cfd0c46fc Mon Sep 17 00:00:00 2001 From: romanszterg Date: Fri, 7 Aug 2020 20:56:21 +0200 Subject: [PATCH 208/515] feat(trading): set is_excluded back to false in case of change --- src/atomic.dex.qt.market.pairs.cpp | 33 +++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/src/atomic.dex.qt.market.pairs.cpp b/src/atomic.dex.qt.market.pairs.cpp index 1b1ddafa96..ff87f4a958 100644 --- a/src/atomic.dex.qt.market.pairs.cpp +++ b/src/atomic.dex.qt.market.pairs.cpp @@ -21,13 +21,13 @@ namespace atomic_dex market_pairs::market_pairs(portfolio_model* portfolio_mdl, QObject* parent) : QObject(parent), m_left_selection_box(new portfolio_proxy_model(portfolio_mdl)), m_right_selection_box(new portfolio_proxy_model(portfolio_mdl)) { - //set_left_selected_coin("KMD"); + // set_left_selected_coin("KMD"); m_left_selection_box->setSourceModel(portfolio_mdl); m_left_selection_box->setFilterRole(portfolio_model::Excluded); m_left_selection_box->setDynamicSortFilter(true); m_left_selection_box->sort_by_currency_balance(false); - //set_right_selected_coin("BTC"); + // set_right_selected_coin("BTC"); m_right_selection_box->setSourceModel(portfolio_mdl); m_right_selection_box->setFilterRole(portfolio_model::Excluded); m_right_selection_box->setDynamicSortFilter(true); @@ -56,6 +56,16 @@ namespace atomic_dex { if (left_coin != m_left_selected_coin) { + //! Set current value back to false + if (not m_left_selected_coin.isEmpty()) + { + auto current_res_left = + m_left_selection_box->match(m_left_selection_box->index(0, 0), portfolio_model::PortfolioRoles::TickerRole, m_left_selected_coin); + assert(not current_res_left.empty()); + m_left_selection_box->setData(current_res_left.at(0), portfolio_model::PortfolioRoles::Excluded, false); + } + + //! Set new one to true m_left_selected_coin = std::move(left_coin); auto res_left = m_left_selection_box->match(m_left_selection_box->index(0, 0), portfolio_model::PortfolioRoles::TickerRole, m_left_selected_coin); assert(not res_left.empty()); @@ -69,20 +79,33 @@ namespace atomic_dex { if (right_coin != m_right_selected_coin) { + //! Set current value back to false + if (not m_right_selected_coin.isEmpty()) + { + auto current_res_right = + m_right_selection_box->match(m_right_selection_box->index(0, 0), portfolio_model::PortfolioRoles::TickerRole, m_right_selected_coin); + assert(not current_res_right.empty()); + m_right_selection_box->setData(current_res_right.at(0), portfolio_model::PortfolioRoles::Excluded, false); + } + + //! Set new one to true m_right_selected_coin = std::move(right_coin); - auto res_right = m_right_selection_box->match(m_right_selection_box->index(0, 0), portfolio_model::PortfolioRoles::TickerRole, m_right_selected_coin); + auto res_right = + m_right_selection_box->match(m_right_selection_box->index(0, 0), portfolio_model::PortfolioRoles::TickerRole, m_right_selected_coin); assert(not res_right.empty()); m_right_selection_box->setData(res_right.at(0), portfolio_model::PortfolioRoles::Excluded, true); emit rightSelectedCoinChanged(); } } - portfolio_proxy_model* market_pairs::get_left_selection_box() const noexcept + portfolio_proxy_model* + market_pairs::get_left_selection_box() const noexcept { return m_left_selection_box; } - portfolio_proxy_model* market_pairs::get_right_selection_box() const noexcept + portfolio_proxy_model* + market_pairs::get_right_selection_box() const noexcept { return m_right_selection_box; } From 17275e6e42143d6fe7fcdf2c42a29c750ee62e08 Mon Sep 17 00:00:00 2001 From: naezith Date: Fri, 7 Aug 2020 22:02:05 +0300 Subject: [PATCH 209/515] feat(gui): at first opening of trade page, set orderbook KMD BTC --- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index 894fc55ee7..69528e54ac 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -175,7 +175,13 @@ Item { onOpened() } + property bool initialized_orderbook_pair: false function onOpened() { + if(!initialized_orderbook_pair) { + initialized_orderbook_pair = true + API.get().trading_pg.set_current_orderbook("KMD", "BTC") + } + fillTickersIfEmpty() reset(true) updateForms() From b2d389cb9f9bcdd2434bc7c08d9e17ecd18598ae Mon Sep 17 00:00:00 2001 From: naezith Date: Sat, 8 Aug 2020 00:24:19 +0300 Subject: [PATCH 210/515] feat(gui): remove all set ticker and ticker list stuff, add new ones --- .../qml/Exchange/Trade/TickerSelector.qml | 52 ++--------- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 88 ++++--------------- 2 files changed, 22 insertions(+), 118 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml b/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml index 3391b24090..ad3876b698 100644 --- a/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml +++ b/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml @@ -14,52 +14,15 @@ RowLayout { layoutDirection: my_side ? Qt.LeftToRight : Qt.RightToLeft property bool my_side: false - property var ticker_list: ([]) - property bool recursive_update: false + property var ticker_list // Public - function setAnyTicker() { - setTicker(getAnyAvailableCoin()) - } - - function fillIfEmpty() { - if(getTicker() === '') setAnyTicker() - } - - function update(new_ticker) { - updateTickerList(new_ticker) - } - function getTicker() { - return ticker_list.length > 0 ? ticker_list[combo.currentIndex].value : "" - } - - function setTicker(ticker) { - combo.currentIndex = getFilteredCoins().map(c => c.ticker).indexOf(ticker) - - // If it doesn't exist, pick an existing one - if(combo.currentIndex === -1) setAnyTicker() + return my_side ? API.get().trading_pg.market_pairs_mdl.left_selected_coin : + API.get().trading_pg.market_pairs_mdl.right_selected_coin } // Private - Timer { - id: update_timer - running: inCurrentPage() - repeat: true - interval: 1000 - onTriggered: { - if(inCurrentPage()) updateTickerList() - } - } - - function updateTickerList(new_ticker) { - recursive_update = new_ticker !== undefined - - ticker_list = General.getTickersAndBalances(getFilteredCoins()) - - update_timer.running = true - } - function getFilteredCoins() { return getCoins(my_side) } @@ -84,17 +47,12 @@ RowLayout { DefaultComboBox { id: combo - Layout.fillWidth: true - model: ticker_list - textRole: "text" + Layout.fillWidth: true onCurrentTextChanged: { - if(!recursive_update) { - updateForms(my_side, combo.currentText) - setPair(my_side) - } + setPair(my_side, currentText) } } } diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index 69528e54ac..ac311585ef 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -151,11 +151,6 @@ Item { // Orderbook - function fillTickersIfEmpty() { - selector_base.fillIfEmpty() - selector_rel.fillIfEmpty() - } - function updateTradeInfo(force=false) { const base = getTicker(sell_mode) const rel = getTicker(!sell_mode) @@ -171,7 +166,7 @@ Item { // Trade function open(ticker) { - setTicker(true, ticker) + // TODO: setPair(true, ticker) onOpened() } @@ -182,25 +177,10 @@ Item { API.get().trading_pg.set_current_orderbook("KMD", "BTC") } - fillTickersIfEmpty() reset(true) - updateForms() setPair(true) } - function updateForms(my_side, new_ticker) { - if(my_side === undefined) { - selector_base.update() - selector_rel.update() - } - else if(my_side) { - selector_rel.update(new_ticker) - } - else { - selector_base.update(new_ticker) - } - } - function moveToBeginning(coins, ticker) { const idx = coins.map(c => c.ticker).indexOf(ticker) if(idx === -1) return @@ -245,34 +225,22 @@ Item { return is_base ? selector_base.getTicker() : selector_rel.getTicker() } - function setTicker(is_base, ticker) { - if(is_base) selector_base.setTicker(ticker) - else selector_rel.setTicker(ticker) - } - - function validBaseRel() { - const base = getTicker(true) - const rel = getTicker(false) - return base !== '' && rel !== '' && base !== rel - } + function setPair(is_base, changed_ticker) { + let base = getTicker(true) + let rel = getTicker(false) - function setPair(is_base) { - if(getTicker(true) === getTicker(false)) { - // Base got selected, same as rel - // Change rel ticker - selector_rel.setAnyTicker() + // Set the new one if it's a change + if(changed_ticker) { + if(is_base) base = changed_ticker + else rel = changed_ticker } - if(validBaseRel()) { - const new_base = getTicker(true) - const rel = getTicker(false) - console.log("Setting current orderbook with params: ", new_base, rel) - API.get().trading_pg.set_current_orderbook(new_base, rel) - reset(true, is_base) - updateTradeInfo() - updateCexPrice(new_base, rel) - exchange.onTradeTickerChanged(new_base) - } + console.log("Setting current orderbook with params: ", base, rel) + API.get().trading_pg.set_current_orderbook(base, rel) + reset(true, is_base) + updateTradeInfo() + updateCexPrice(base, rel) + exchange.onTradeTickerChanged(base) } function trade(base, rel, options) { @@ -326,37 +294,12 @@ Item { } } - // No coins warning - ColumnLayout { - anchors.centerIn: parent - visible: selector_base.ticker_list.length === 0 - - DefaultImage { - Layout.alignment: Qt.AlignHCenter - source: General.image_path + "setup-wallet-restore-2.svg" - Layout.bottomMargin: 30 - } - - DefaultText { - Layout.alignment: Qt.AlignHCenter - text_value: API.get().empty_string + (qsTr("No balance available")) - font.pixelSize: Style.textSize2 - } - - DefaultText { - Layout.alignment: Qt.AlignHCenter - text_value: API.get().empty_string + (qsTr("Please enable a coin with balance or deposit funds")) - } - } - // Form ColumnLayout { id: form spacing: layout_margin - visible: selector_base.ticker_list.length > 0 - anchors.fill: parent Item { @@ -397,6 +340,7 @@ Item { TickerSelector { id: selector_base my_side: true + ticker_list: API.get().trading_pg.market_pairs_mdl.left_selection_box Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter } @@ -410,6 +354,8 @@ Item { TickerSelector { id: selector_rel + my_side: false + ticker_list: API.get().trading_pg.market_pairs_mdl.right_selection_box Layout.alignment: Qt.AlignRight | Qt.AlignVCenter } } From 55a6ea209eda8678776f9555c3395411b21ceb99 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Sat, 8 Aug 2020 00:09:47 +0200 Subject: [PATCH 211/515] feat(trading): add display role for portfolio data --- src/atomic.dex.qt.market.pairs.cpp | 4 ++-- src/atomic.dex.qt.portfolio.data.hpp | 2 ++ src/atomic.dex.qt.portfolio.model.cpp | 16 +++++++++++++--- src/atomic.dex.qt.portfolio.model.hpp | 3 ++- ...tomic.dex.qt.portfolio.proxy.filter.model.cpp | 5 ++++- 5 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/atomic.dex.qt.market.pairs.cpp b/src/atomic.dex.qt.market.pairs.cpp index ff87f4a958..6da8ae90aa 100644 --- a/src/atomic.dex.qt.market.pairs.cpp +++ b/src/atomic.dex.qt.market.pairs.cpp @@ -23,13 +23,13 @@ namespace atomic_dex { // set_left_selected_coin("KMD"); m_left_selection_box->setSourceModel(portfolio_mdl); - m_left_selection_box->setFilterRole(portfolio_model::Excluded); + //m_left_selection_box->setFilterRole(portfolio_model::Excluded); m_left_selection_box->setDynamicSortFilter(true); m_left_selection_box->sort_by_currency_balance(false); // set_right_selected_coin("BTC"); m_right_selection_box->setSourceModel(portfolio_mdl); - m_right_selection_box->setFilterRole(portfolio_model::Excluded); + //m_right_selection_box->setFilterRole(portfolio_model::Excluded); m_right_selection_box->setDynamicSortFilter(true); m_right_selection_box->sort_by_currency_balance(false); } diff --git a/src/atomic.dex.qt.portfolio.data.hpp b/src/atomic.dex.qt.portfolio.data.hpp index 31e40a3049..8f91defbd4 100644 --- a/src/atomic.dex.qt.portfolio.data.hpp +++ b/src/atomic.dex.qt.portfolio.data.hpp @@ -45,5 +45,7 @@ namespace atomic_dex QJsonArray trend_7d; bool is_excluded{false}; + + QString display; }; } // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.portfolio.model.cpp b/src/atomic.dex.qt.portfolio.model.cpp index b8e9d2267a..2e24f9e8b5 100644 --- a/src/atomic.dex.qt.portfolio.model.cpp +++ b/src/atomic.dex.qt.portfolio.model.cpp @@ -70,7 +70,10 @@ namespace atomic_dex .main_currency_balance = QString::fromStdString(paprika.get_price_in_fiat(m_config.current_currency, coin.ticker, ec)), .change_24h = change_24h, .main_currency_price_for_one_unit = QString::fromStdString(paprika.get_rate_conversion(m_config.current_currency, coin.ticker, ec, true)), - .trend_7d = nlohmann_json_array_to_qt_json_array(paprika.get_ticker_historical(coin.ticker).answer)}; + .trend_7d = nlohmann_json_array_to_qt_json_array(paprika.get_ticker_historical(coin.ticker).answer), + .is_excluded = false, + }; + data.display = data.ticker + "(" + data.balance + ")"; spdlog::trace( "inserting ticker {} with name {} balance {} main currency balance {}", coin.ticker, coin.name, data.balance.toStdString(), data.main_currency_balance.toStdString()); @@ -103,6 +106,8 @@ namespace atomic_dex update_value(Change24H, change24_h, idx, *this); const QString balance = QString::fromStdString(mm2_system.my_balance(coin.ticker, ec)); update_value(BalanceRole, balance, idx, *this); + const QString display = QString::fromStdString(coin.ticker) + "(" + balance + ")"; + update_value(Display, display, idx, *this); } })); } @@ -155,6 +160,8 @@ namespace atomic_dex return item.trend_7d; case Excluded: return item.is_excluded; + case Display: + return item.display; } return {}; } @@ -188,6 +195,9 @@ namespace atomic_dex case Excluded: item.is_excluded = value.toBool(); break; + case Display: + item.display = value.toString(); + break; default: return false; } @@ -235,8 +245,8 @@ namespace atomic_dex return {{TickerRole, "ticker"}, {NameRole, "name"}, {BalanceRole, "balance"}, {MainCurrencyBalanceRole, "main_currency_balance"}, {Change24H, "change_24h"}, {MainCurrencyPriceForOneUnit, "main_currency_price_for_one_unit"}, - {Trend7D, "trend_7d"}, - {Excluded, "excluded"}}; + {Trend7D, "trend_7d"}, {Excluded, "excluded"}, + {Display, "display"}}; } portfolio_proxy_model* diff --git a/src/atomic.dex.qt.portfolio.model.hpp b/src/atomic.dex.qt.portfolio.model.hpp index 2e7b07873b..6b89ef60c4 100644 --- a/src/atomic.dex.qt.portfolio.model.hpp +++ b/src/atomic.dex.qt.portfolio.model.hpp @@ -48,7 +48,8 @@ namespace atomic_dex Change24H, MainCurrencyPriceForOneUnit, Trend7D, - Excluded + Excluded, + Display }; private: diff --git a/src/atomic.dex.qt.portfolio.proxy.filter.model.cpp b/src/atomic.dex.qt.portfolio.proxy.filter.model.cpp index 428f2e3a2c..fa6efe4395 100644 --- a/src/atomic.dex.qt.portfolio.proxy.filter.model.cpp +++ b/src/atomic.dex.qt.portfolio.proxy.filter.model.cpp @@ -92,6 +92,8 @@ namespace atomic_dex return false; case portfolio_model::Excluded: return false; + case portfolio_model::Display: + return false; } } @@ -100,7 +102,8 @@ namespace atomic_dex { QModelIndex idx = this->sourceModel()->index(source_row, 0, source_parent); assert(this->sourceModel()->hasIndex(idx.row(), 0)); - bool is_excluded = this->sourceModel()->data(idx, this->filterRole()).toBool(); + bool is_excluded = this->sourceModel()->data(idx, atomic_dex::portfolio_model::Excluded).toBool(); + spdlog::trace("is excluded: {}", is_excluded); if (is_excluded) { return false; From 6cf583b188c1d2d9c65132090205801c63421841 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Sat, 8 Aug 2020 00:30:41 +0200 Subject: [PATCH 212/515] feat(trading): add space --- src/atomic.dex.qt.portfolio.model.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/atomic.dex.qt.portfolio.model.cpp b/src/atomic.dex.qt.portfolio.model.cpp index 2e24f9e8b5..eae1ab677c 100644 --- a/src/atomic.dex.qt.portfolio.model.cpp +++ b/src/atomic.dex.qt.portfolio.model.cpp @@ -73,7 +73,7 @@ namespace atomic_dex .trend_7d = nlohmann_json_array_to_qt_json_array(paprika.get_ticker_historical(coin.ticker).answer), .is_excluded = false, }; - data.display = data.ticker + "(" + data.balance + ")"; + data.display = data.ticker + " (" + data.balance + ")"; spdlog::trace( "inserting ticker {} with name {} balance {} main currency balance {}", coin.ticker, coin.name, data.balance.toStdString(), data.main_currency_balance.toStdString()); @@ -106,7 +106,7 @@ namespace atomic_dex update_value(Change24H, change24_h, idx, *this); const QString balance = QString::fromStdString(mm2_system.my_balance(coin.ticker, ec)); update_value(BalanceRole, balance, idx, *this); - const QString display = QString::fromStdString(coin.ticker) + "(" + balance + ")"; + const QString display = QString::fromStdString(coin.ticker) + " (" + balance + ")"; update_value(Display, display, idx, *this); } })); From 9fad39af300c2d501c7dd174c478041c573d56fe Mon Sep 17 00:00:00 2001 From: naezith Date: Sat, 8 Aug 2020 01:42:29 +0300 Subject: [PATCH 213/515] feat(gui): use display and ticker fields for combobox --- .../qml/Exchange/Trade/TickerSelector.qml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml b/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml index ad3876b698..55502c3f10 100644 --- a/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml +++ b/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml @@ -1,6 +1,6 @@ import QtQuick 2.12 import QtQuick.Layouts 1.12 -import QtQuick.Controls 2.12 +import QtQuick.Controls 2.14 import QtGraphicalEffects 1.0 import "../../Components" @@ -48,11 +48,12 @@ RowLayout { id: combo model: ticker_list + textRole: "display" + valueRole: "ticker" + onCurrentValueChanged: { + setPair(my_side, currentValue) + } Layout.fillWidth: true - - onCurrentTextChanged: { - setPair(my_side, currentText) - } } } From 7a3251ed15e420401dfaae03f3dcdcd55d35f42e Mon Sep 17 00:00:00 2001 From: naezith Date: Sat, 8 Aug 2020 02:00:05 +0300 Subject: [PATCH 214/515] feat(gui): bind backend selected ticker to combobox currentIndex --- .../qml/Exchange/Trade/TickerSelector.qml | 15 ++++++++------- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 4 +++- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml b/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml index 55502c3f10..4c48d9527e 100644 --- a/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml +++ b/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml @@ -15,12 +15,7 @@ RowLayout { property bool my_side: false property var ticker_list - - // Public - function getTicker() { - return my_side ? API.get().trading_pg.market_pairs_mdl.left_selected_coin : - API.get().trading_pg.market_pairs_mdl.right_selected_coin - } + property string ticker // Private function getFilteredCoins() { @@ -39,17 +34,23 @@ RowLayout { } DefaultImage { - source: General.coinIcon(getTicker()) + source: General.coinIcon(ticker) Layout.preferredWidth: 32 Layout.preferredHeight: Layout.preferredWidth } + + onTickerChanged: { + combo.currentIndex = combo.indexOfValue(ticker) + } + DefaultComboBox { id: combo model: ticker_list textRole: "display" valueRole: "ticker" + onCurrentValueChanged: { setPair(my_side, currentValue) } diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index ac311585ef..948fa66da8 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -222,7 +222,7 @@ Item { } function getTicker(is_base) { - return is_base ? selector_base.getTicker() : selector_rel.getTicker() + return is_base ? selector_base.ticker : selector_rel.ticker } function setPair(is_base, changed_ticker) { @@ -341,6 +341,7 @@ Item { id: selector_base my_side: true ticker_list: API.get().trading_pg.market_pairs_mdl.left_selection_box + ticker: API.get().trading_pg.market_pairs_mdl.left_selected_coin Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter } @@ -356,6 +357,7 @@ Item { id: selector_rel my_side: false ticker_list: API.get().trading_pg.market_pairs_mdl.right_selection_box + ticker: API.get().trading_pg.market_pairs_mdl.right_selected_coin Layout.alignment: Qt.AlignRight | Qt.AlignVCenter } } From 4e7be198a805ade156df01448eff82723f37ceab Mon Sep 17 00:00:00 2001 From: naezith Date: Sat, 8 Aug 2020 02:04:53 +0300 Subject: [PATCH 215/515] feat(gui): less usage of getTicker, use selector_base/rel.ticker instead --- atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml | 2 +- atomic_qt_design/qml/Exchange/Trade/OrderForm.qml | 8 ++++---- atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml | 8 ++++---- atomic_qt_design/qml/Exchange/Trade/PriceLine.qml | 8 ++++---- atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml | 4 +--- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 6 +++--- 6 files changed, 17 insertions(+), 19 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml index 6619c091d9..86ca7e7719 100644 --- a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml +++ b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml @@ -231,7 +231,7 @@ DefaultModal { text: API.get().empty_string + (qsTr("Confirm")) Layout.fillWidth: true onClicked: { - trade(getTicker(true), getTicker(false), { + trade(selector_base.ticker, selector_rel.ticker, { enable_custom_config: enable_custom_config.checked, is_dpow_configurable: config_section.is_dpow_configurable, enable_dpow_confs: enable_dpow_confs.checked, diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index 8a1beeec89..52d0faa8c6 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -212,7 +212,7 @@ FloatingBackground { enabled: input_volume.field.enabled field.left_text: API.get().empty_string + (qsTr("Price")) - field.right_text: getTicker(false) + field.right_text: selector_rel.ticker field.onTextChanged: { onInputChanged() @@ -241,7 +241,7 @@ FloatingBackground { field.enabled: root.enabled && !shouldBlockInput() field.left_text: API.get().empty_string + (qsTr("Volume")) - field.right_text: getTicker(true) + field.right_text: selector_base.ticker field.placeholderText: API.get().empty_string + (my_side ? qsTr("Amount to sell") : qsTr("Amount to receive")) field.onTextChanged: { const before_checks = field.text @@ -408,7 +408,7 @@ FloatingBackground { DefaultText { Layout.alignment: Qt.AlignLeft - text_value: API.get().empty_string + (qsTr("Total") + ": " + General.formatCrypto("", total_amount, getTicker(false))) + text_value: API.get().empty_string + (qsTr("Total") + ": " + General.formatCrypto("", total_amount, selector_rel.ticker)) font.pixelSize: Style.textSizeSmall3 } @@ -422,7 +422,7 @@ FloatingBackground { width: 170 - text: API.get().empty_string + (my_side ? qsTr("Sell %1", "TICKER").arg(getTicker(true)) : qsTr("Buy %1", "TICKER").arg(getTicker(true))) + text: API.get().empty_string + (my_side ? qsTr("Sell %1", "TICKER").arg(selector_base.ticker) : qsTr("Buy %1", "TICKER").arg(selector_base.ticker)) enabled: valid_trade_info && !notEnoughBalanceForFees() && isValid() onClicked: confirm_trade_modal.open() } diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml index b0bbdb63b6..fc8b65674e 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml @@ -24,8 +24,8 @@ ColumnLayout { id: price_header font.pixelSize: Style.textSizeSmall2 - text_value: API.get().empty_string + (is_asks ? qsTr("Ask Price") + "\n(" + getTicker(false) + ")": - qsTr("Bid Price") + "\n(" + getTicker(false) + ")") + text_value: API.get().empty_string + (is_asks ? qsTr("Ask Price") + "\n(" + selector_rel.ticker + ")": + qsTr("Bid Price") + "\n(" + selector_rel.ticker + ")") color: is_asks ? Style.colorRed : Style.colorGreen horizontalAlignment: is_asks ? Text.AlignLeft : Text.AlignRight @@ -50,7 +50,7 @@ ColumnLayout { font.pixelSize: price_header.font.pixelSize - text_value: API.get().empty_string + (qsTr("Quantity") + "\n(" + getTicker(true) + ")") + text_value: API.get().empty_string + (qsTr("Quantity") + "\n(" + selector_base.ticker + ")") color: Style.colorWhite1 anchors.verticalCenter: parent.verticalCenter } @@ -67,7 +67,7 @@ ColumnLayout { font.pixelSize: price_header.font.pixelSize - text_value: API.get().empty_string + (qsTr("Total") + "\n(" + getTicker(false) + ")") + text_value: API.get().empty_string + (qsTr("Total") + "\n(" + selector_rel.ticker + ")") color: Style.colorWhite1 anchors.verticalCenter: parent.verticalCenter } diff --git a/atomic_qt_design/qml/Exchange/Trade/PriceLine.qml b/atomic_qt_design/qml/Exchange/Trade/PriceLine.qml index 3058b77736..7a6c466b54 100644 --- a/atomic_qt_design/qml/Exchange/Trade/PriceLine.qml +++ b/atomic_qt_design/qml/Exchange/Trade/PriceLine.qml @@ -47,7 +47,7 @@ RowLayout { // Price reversed DefaultText { Layout.alignment: Qt.AlignHCenter - text_value: API.get().empty_string + ("1 " + getTicker(false) + " = " + General.formatCrypto("", General.formatDouble(1 / parseFloat(price)), getTicker(true))) + text_value: API.get().empty_string + ("1 " + selector_rel.ticker + " = " + General.formatCrypto("", General.formatDouble(1 / parseFloat(price)), selector_base.ticker)) font.pixelSize: fontSizeBigger font.bold: true } @@ -55,7 +55,7 @@ RowLayout { // Price DefaultText { Layout.alignment: Qt.AlignHCenter - text_value: API.get().empty_string + ("1 " + getTicker(true) + " = " + General.formatCrypto("", price, getTicker(false))) + text_value: API.get().empty_string + ("1 " + selector_base.ticker + " = " + General.formatCrypto("", price, selector_rel.ticker)) font.pixelSize: fontSize } } @@ -126,7 +126,7 @@ RowLayout { // Price reversed DefaultText { Layout.alignment: Qt.AlignHCenter - text_value: API.get().empty_string + ("1 " + getTicker(false) + " = " + General.formatCrypto("", General.formatDouble(1 / parseFloat(cex_price)), getTicker(true))) + text_value: API.get().empty_string + ("1 " + selector_rel.ticker + " = " + General.formatCrypto("", General.formatDouble(1 / parseFloat(cex_price)), selector_base.ticker)) font.pixelSize: fontSizeBigger font.bold: true } @@ -134,7 +134,7 @@ RowLayout { // Price DefaultText { Layout.alignment: Qt.AlignHCenter - text_value: API.get().empty_string + ("1 " + getTicker(true) + " = " + General.formatCrypto("", cex_price, getTicker(false))) + text_value: API.get().empty_string + ("1 " + selector_base.ticker + " = " + General.formatCrypto("", cex_price, selector_rel.ticker)) font.pixelSize: fontSize } } diff --git a/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml b/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml index 4c48d9527e..c38490da1a 100644 --- a/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml +++ b/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml @@ -51,9 +51,7 @@ RowLayout { textRole: "display" valueRole: "ticker" - onCurrentValueChanged: { - setPair(my_side, currentValue) - } + onCurrentValueChanged: setPair(my_side, currentValue) Layout.fillWidth: true } diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index 948fa66da8..1e2be1cd83 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -212,7 +212,7 @@ Item { // Filter for Receive else { return coins.filter(c => { - if(c.ticker === getTicker(true)) return false + if(c.ticker === selector_base.ticker) return false c.balance = API.get().get_balance(c.ticker) @@ -226,8 +226,8 @@ Item { } function setPair(is_base, changed_ticker) { - let base = getTicker(true) - let rel = getTicker(false) + let base = selector_base.ticker + let rel = selector_rel.ticker // Set the new one if it's a change if(changed_ticker) { From 154856cf61d153a5c54dbbe2d079ae895d47aab6 Mon Sep 17 00:00:00 2001 From: naezith Date: Sat, 8 Aug 2020 02:13:49 +0300 Subject: [PATCH 216/515] feat(gui): base/rel_ticker left/right_ticker instead of getTicker --- atomic_qt_design/qml/Constants/General.qml | 19 --------------- .../qml/Exchange/Trade/ConfirmTradeModal.qml | 2 +- .../qml/Exchange/Trade/OrderForm.qml | 12 +++++----- .../qml/Exchange/Trade/PriceLine.qml | 8 +++---- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 24 +++++++++++-------- 5 files changed, 25 insertions(+), 40 deletions(-) diff --git a/atomic_qt_design/qml/Constants/General.qml b/atomic_qt_design/qml/Constants/General.qml index 6eef9cae51..0da2f9480e 100644 --- a/atomic_qt_design/qml/Constants/General.qml +++ b/atomic_qt_design/qml/Constants/General.qml @@ -170,25 +170,6 @@ QtObject { }) } - function getTickers(coins) { - return coins.map(c => { - return { value: c.ticker, text: c.ticker } - }) - } - - - function tickerAndBalance(ticker) { - return ticker + " (" + API.get().get_balance(ticker) + ")" - } - - function getTickersAndBalances(coins) { - const privacy_on = General.privacy_mode - const privacy_text = General.privacy_text - return coins.map(c => { - return { value: c.ticker, text: c.ticker + " (" + (privacy_on ? privacy_text : c.balance) + ")" } - }) - } - function getMinTradeAmount() { return 0.00777 } diff --git a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml index 86ca7e7719..dc5a9153cd 100644 --- a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml +++ b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml @@ -231,7 +231,7 @@ DefaultModal { text: API.get().empty_string + (qsTr("Confirm")) Layout.fillWidth: true onClicked: { - trade(selector_base.ticker, selector_rel.ticker, { + trade(left_ticker, right_ticker, { enable_custom_config: enable_custom_config.checked, is_dpow_configurable: config_section.is_dpow_configurable, enable_dpow_confs: enable_dpow_confs.checked, diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index 52d0faa8c6..3c0413741c 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -62,8 +62,8 @@ FloatingBackground { // set_as_current should be true if input_volume is updated // if it's called for cap check, it should be false because that's not the current input_volume - const base = getTicker(sell_mode) - const rel = getTicker(!sell_mode) + const base = base_ticker + const rel = rel_ticker const amount = getMaxVolume() if(base === '' || rel === '') return 0 @@ -212,7 +212,7 @@ FloatingBackground { enabled: input_volume.field.enabled field.left_text: API.get().empty_string + (qsTr("Price")) - field.right_text: selector_rel.ticker + field.right_text: right_ticker field.onTextChanged: { onInputChanged() @@ -241,7 +241,7 @@ FloatingBackground { field.enabled: root.enabled && !shouldBlockInput() field.left_text: API.get().empty_string + (qsTr("Volume")) - field.right_text: selector_base.ticker + field.right_text: left_ticker field.placeholderText: API.get().empty_string + (my_side ? qsTr("Amount to sell") : qsTr("Amount to receive")) field.onTextChanged: { const before_checks = field.text @@ -408,7 +408,7 @@ FloatingBackground { DefaultText { Layout.alignment: Qt.AlignLeft - text_value: API.get().empty_string + (qsTr("Total") + ": " + General.formatCrypto("", total_amount, selector_rel.ticker)) + text_value: API.get().empty_string + (qsTr("Total") + ": " + General.formatCrypto("", total_amount, right_ticker)) font.pixelSize: Style.textSizeSmall3 } @@ -422,7 +422,7 @@ FloatingBackground { width: 170 - text: API.get().empty_string + (my_side ? qsTr("Sell %1", "TICKER").arg(selector_base.ticker) : qsTr("Buy %1", "TICKER").arg(selector_base.ticker)) + text: API.get().empty_string + (my_side ? qsTr("Sell %1", "TICKER").arg(left_ticker) : qsTr("Buy %1", "TICKER").arg(left_ticker)) enabled: valid_trade_info && !notEnoughBalanceForFees() && isValid() onClicked: confirm_trade_modal.open() } diff --git a/atomic_qt_design/qml/Exchange/Trade/PriceLine.qml b/atomic_qt_design/qml/Exchange/Trade/PriceLine.qml index 7a6c466b54..4b0a3221d4 100644 --- a/atomic_qt_design/qml/Exchange/Trade/PriceLine.qml +++ b/atomic_qt_design/qml/Exchange/Trade/PriceLine.qml @@ -47,7 +47,7 @@ RowLayout { // Price reversed DefaultText { Layout.alignment: Qt.AlignHCenter - text_value: API.get().empty_string + ("1 " + selector_rel.ticker + " = " + General.formatCrypto("", General.formatDouble(1 / parseFloat(price)), selector_base.ticker)) + text_value: API.get().empty_string + ("1 " + right_ticker + " = " + General.formatCrypto("", General.formatDouble(1 / parseFloat(price)), left_ticker)) font.pixelSize: fontSizeBigger font.bold: true } @@ -55,7 +55,7 @@ RowLayout { // Price DefaultText { Layout.alignment: Qt.AlignHCenter - text_value: API.get().empty_string + ("1 " + selector_base.ticker + " = " + General.formatCrypto("", price, selector_rel.ticker)) + text_value: API.get().empty_string + ("1 " + left_ticker + " = " + General.formatCrypto("", price, right_ticker)) font.pixelSize: fontSize } } @@ -126,7 +126,7 @@ RowLayout { // Price reversed DefaultText { Layout.alignment: Qt.AlignHCenter - text_value: API.get().empty_string + ("1 " + selector_rel.ticker + " = " + General.formatCrypto("", General.formatDouble(1 / parseFloat(cex_price)), selector_base.ticker)) + text_value: API.get().empty_string + ("1 " + right_ticker + " = " + General.formatCrypto("", General.formatDouble(1 / parseFloat(cex_price)), left_ticker)) font.pixelSize: fontSizeBigger font.bold: true } @@ -134,7 +134,7 @@ RowLayout { // Price DefaultText { Layout.alignment: Qt.AlignHCenter - text_value: API.get().empty_string + ("1 " + selector_base.ticker + " = " + General.formatCrypto("", cex_price, selector_rel.ticker)) + text_value: API.get().empty_string + ("1 " + left_ticker + " = " + General.formatCrypto("", cex_price, right_ticker)) font.pixelSize: fontSize } } diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index 1e2be1cd83..20245961ba 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -12,6 +12,10 @@ Item { property string action_result property bool sell_mode: true + property string left_ticker: selector_left.ticker + property string right_ticker: selector_right.ticker + property string base_ticker: sell_mode ? left_ticker : right_ticker + property string rel_ticker: sell_mode ? right_ticker : left_ticker // Override property var onOrderSuccess: () => {} @@ -152,8 +156,8 @@ Item { // Orderbook function updateTradeInfo(force=false) { - const base = getTicker(sell_mode) - const rel = getTicker(!sell_mode) + const base = base_ticker + const rel = rel_ticker const amount = sell_mode ? getCurrentForm().getVolume() : General.formatDouble(getCurrentForm().getNeededAmountToSpend(getCurrentForm().getVolume())) if(force || (General.fieldExists(base) && General.fieldExists(rel) && !General.isZero(amount))) { @@ -212,7 +216,7 @@ Item { // Filter for Receive else { return coins.filter(c => { - if(c.ticker === selector_base.ticker) return false + if(c.ticker === left_ticker) return false c.balance = API.get().get_balance(c.ticker) @@ -222,12 +226,12 @@ Item { } function getTicker(is_base) { - return is_base ? selector_base.ticker : selector_rel.ticker + return is_base ? left_ticker : right_ticker } function setPair(is_base, changed_ticker) { - let base = selector_base.ticker - let rel = selector_rel.ticker + let base = left_ticker + let rel = right_ticker // Set the new one if it's a change if(changed_ticker) { @@ -338,7 +342,7 @@ Item { spacing: 40 TickerSelector { - id: selector_base + id: selector_left my_side: true ticker_list: API.get().trading_pg.market_pairs_mdl.left_selection_box ticker: API.get().trading_pg.market_pairs_mdl.left_selected_coin @@ -354,7 +358,7 @@ Item { } TickerSelector { - id: selector_rel + id: selector_right my_side: false ticker_list: API.get().trading_pg.market_pairs_mdl.right_selection_box ticker: API.get().trading_pg.market_pairs_mdl.right_selected_coin @@ -424,9 +428,9 @@ Item { text_value: API.get().empty_string + ( General.isZero(getCurrentPrice()) ? (qsTr("Please fill the price field")) : - notEnoughBalance() ? (qsTr("%1 balance is lower than minimum trade amount").arg(getTicker(sell_mode)) + " : " + General.getMinTradeAmount()) : + notEnoughBalance() ? (qsTr("%1 balance is lower than minimum trade amount").arg(base_ticker) + " : " + General.getMinTradeAmount()) : notEnoughBalanceForFees() ? - (qsTr("Not enough balance for the fees. Need at least %1 more", "AMT TICKER").arg(General.formatCrypto("", parseFloat(curr_trade_info.amount_needed), getTicker(sell_mode)))) : + (qsTr("Not enough balance for the fees. Need at least %1 more", "AMT TICKER").arg(General.formatCrypto("", parseFloat(curr_trade_info.amount_needed), base_ticker))) : General.isZero(getCurrentForm().getVolume()) ? (qsTr("Please fill the volume field")) : (getCurrentForm().hasEthFees() && !getCurrentForm().hasEnoughEthForFees()) ? (qsTr("Not enough ETH for the transaction fee")) : (getCurrentForm().fieldsAreFilled() && !getCurrentForm().higherThanMinTradeAmount()) ? ((qsTr("Amount is lower than minimum trade amount")) + " : " + General.getMinTradeAmount()) : "" From 60708e7493ba1b852ccbc6b302584d87d9b1576a Mon Sep 17 00:00:00 2001 From: naezith Date: Sat, 8 Aug 2020 02:16:32 +0300 Subject: [PATCH 217/515] feat(gui): rename my_side to left_side for ticker selector --- atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml | 8 ++++---- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml b/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml index c38490da1a..0d68ab2911 100644 --- a/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml +++ b/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml @@ -11,15 +11,15 @@ RowLayout { spacing: 5 Layout.preferredWidth: 250 - layoutDirection: my_side ? Qt.LeftToRight : Qt.RightToLeft + layoutDirection: left_side ? Qt.LeftToRight : Qt.RightToLeft - property bool my_side: false + property bool left_side: false property var ticker_list property string ticker // Private function getFilteredCoins() { - return getCoins(my_side) + return getCoins(left_side) } function getAnyAvailableCoin(filter_ticker) { @@ -51,7 +51,7 @@ RowLayout { textRole: "display" valueRole: "ticker" - onCurrentValueChanged: setPair(my_side, currentValue) + onCurrentValueChanged: setPair(left_side, currentValue) Layout.fillWidth: true } diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index 20245961ba..6e1628cc6c 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -343,7 +343,7 @@ Item { TickerSelector { id: selector_left - my_side: true + left_side: true ticker_list: API.get().trading_pg.market_pairs_mdl.left_selection_box ticker: API.get().trading_pg.market_pairs_mdl.left_selected_coin Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter @@ -359,7 +359,7 @@ Item { TickerSelector { id: selector_right - my_side: false + left_side: false ticker_list: API.get().trading_pg.market_pairs_mdl.right_selection_box ticker: API.get().trading_pg.market_pairs_mdl.right_selected_coin Layout.alignment: Qt.AlignRight | Qt.AlignVCenter From fd0a77c1fd8b13a685ff080827817eada66ee5f5 Mon Sep 17 00:00:00 2001 From: naezith Date: Sat, 8 Aug 2020 02:18:15 +0300 Subject: [PATCH 218/515] feat(gui): rename my_side to is_sell_form at orderform & similar changes --- .../qml/Exchange/Trade/ConfirmTradeModal.qml | 8 ++--- .../qml/Exchange/Trade/OrderForm.qml | 34 +++++++++---------- .../qml/Exchange/Trade/OrderbookSection.qml | 8 ++--- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 8 ++--- 4 files changed, 29 insertions(+), 29 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml index dc5a9153cd..ef53fe9042 100644 --- a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml +++ b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml @@ -36,8 +36,8 @@ DefaultModal { Layout.alignment: Qt.AlignHCenter details: ({ - base_coin: getTicker(sell_mode), - rel_coin: getTicker(!sell_mode), + base_coin: base_ticker, + rel_coin: rel_ticker, base_amount: sell_mode ? getCurrentForm().field.text : getCurrentForm().total_amount, rel_amount: sell_mode ? getCurrentForm().total_amount : getCurrentForm().field.text, @@ -93,7 +93,7 @@ DefaultModal { ColumnLayout { id: config_section - readonly property bool is_dpow_configurable: API.get().get_coin_info(getTicker(!sell_mode)).type === "Smart Chain" + readonly property bool is_dpow_configurable: API.get().get_coin_info(rel_ticker).type === "Smart Chain" Layout.bottomMargin: 10 Layout.alignment: Qt.AlignHCenter @@ -122,7 +122,7 @@ DefaultModal { Layout.alignment: Qt.AlignHCenter id: enable_custom_config - text: API.get().empty_string + (qsTr("Use custom protection settings for incoming %1 transactions", "TICKER").arg(getTicker(!sell_mode))) + text: API.get().empty_string + (qsTr("Use custom protection settings for incoming %1 transactions", "TICKER").arg(rel_ticker)) } // Configuration settings diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index 3c0413741c..f4caca231c 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -11,7 +11,7 @@ FloatingBackground { property alias field: input_volume.field property alias price_field: input_price.field - property bool my_side: false + property bool is_sell_form: false property bool enabled: true property alias column_layout: form_layout property string total_amount: "0" @@ -48,14 +48,14 @@ FloatingBackground { if(valid) valid = higherThanMinTradeAmount() if(valid) valid = !notEnoughBalance() - if(valid) valid = API.get().do_i_have_enough_funds(getTicker(my_side), General.formatDouble(getNeededAmountToSpend(input_volume.field.text))) + if(valid) valid = API.get().do_i_have_enough_funds(getTicker(is_sell_form), General.formatDouble(getNeededAmountToSpend(input_volume.field.text))) if(valid && hasEthFees()) valid = hasEnoughEthForFees() return valid } function getMaxVolume() { - return API.get().get_balance(getTicker(my_side)) + return API.get().get_balance(getTicker(is_sell_form)) } function getMaxTradableVolume(set_as_current) { @@ -70,7 +70,7 @@ FloatingBackground { const info = getTradeInfo(base, rel, amount, set_as_current) const my_amt = parseFloat(valid_trade_info ? info.input_final_value : amount) - if(my_side) return my_amt + if(is_sell_form) return my_amt // If it's buy side, then volume input needs to be calculated with the current price const price = parseFloat(getCurrentPrice()) @@ -80,7 +80,7 @@ FloatingBackground { function reset(is_base) { input_price.field.text = '' - if(my_side) { + if(is_sell_form) { // is_base info comes from the ComboBox ticker change in OrderForm. // At other places it's not given. // We don't want to reset base balance at rel ticker change @@ -97,7 +97,7 @@ FloatingBackground { function capVolume() { if(inCurrentPage() && input_volume.field.acceptableInput) { // If price is 0 at buy side, don't cap it to 0, let the user edit - if(!my_side && General.isZero(getCurrentPrice())) + if(!is_sell_form && General.isZero(getCurrentPrice())) return false const input_volume_value = parseFloat(input_volume.field.text) @@ -127,13 +127,13 @@ FloatingBackground { function getNeededAmountToSpend(volume) { volume = parseFloat(volume) - if(my_side) return volume + if(is_sell_form) return volume else return volume * parseFloat(getCurrentPrice()) } function notEnoughBalance() { // If sell side or buy side but there is no price, then just check the balance - if(my_side || General.isZero(getCurrentPrice())) { + if(is_sell_form || General.isZero(getCurrentPrice())) { return parseFloat(getMaxVolume()) < General.getMinTradeAmount() } @@ -242,7 +242,7 @@ FloatingBackground { field.left_text: API.get().empty_string + (qsTr("Volume")) field.right_text: left_ticker - field.placeholderText: API.get().empty_string + (my_side ? qsTr("Amount to sell") : qsTr("Amount to receive")) + field.placeholderText: API.get().empty_string + (is_sell_form ? qsTr("Amount to sell") : qsTr("Amount to receive")) field.onTextChanged: { const before_checks = field.text onInputChanged() @@ -262,7 +262,7 @@ FloatingBackground { anchors.top: input_volume.bottom anchors.topMargin: 5 - text_value: getFiatText(input_volume.field.text, getTicker(my_side)) + text_value: getFiatText(input_volume.field.text, getTicker(is_sell_form)) font.pixelSize: input_volume.field.font.pixelSize CexInfoTrigger {} @@ -279,7 +279,7 @@ FloatingBackground { property bool updating_from_text_field: false property bool updating_text_field: false readonly property int precision: General.getRecommendedPrecision(to) - visible: my_side + visible: is_sell_form Layout.fillWidth: true Layout.leftMargin: top_line.Layout.leftMargin Layout.rightMargin: top_line.Layout.rightMargin @@ -355,14 +355,14 @@ FloatingBackground { DefaultText { id: tx_fee_text - text_value: API.get().empty_string + ((qsTr('Transaction Fee') + ': ' + General.formatCrypto("", curr_trade_info.tx_fee, curr_trade_info.is_ticker_of_fees_eth ? "ETH" : getTicker(my_side))) + + text_value: API.get().empty_string + ((qsTr('Transaction Fee') + ': ' + General.formatCrypto("", curr_trade_info.tx_fee, curr_trade_info.is_ticker_of_fees_eth ? "ETH" : getTicker(is_sell_form))) + // ETH Fees (hasEthFees() ? " + " + General.formatCrypto("", curr_trade_info.erc_fees, 'ETH') : '') + // Fiat part (" ("+ getFiatText(!hasEthFees() ? curr_trade_info.tx_fee : General.formatDouble((parseFloat(curr_trade_info.tx_fee) + parseFloat(curr_trade_info.erc_fees))), - curr_trade_info.is_ticker_of_fees_eth ? 'ETH' : getTicker(my_side)) + curr_trade_info.is_ticker_of_fees_eth ? 'ETH' : getTicker(is_sell_form)) +")") @@ -373,11 +373,11 @@ FloatingBackground { } DefaultText { - text_value: API.get().empty_string + (qsTr('Trading Fee') + ': ' + General.formatCrypto("", curr_trade_info.trade_fee, getTicker(my_side)) + + text_value: API.get().empty_string + (qsTr('Trading Fee') + ': ' + General.formatCrypto("", curr_trade_info.trade_fee, getTicker(is_sell_form)) + // Fiat part (" ("+ - getFiatText(curr_trade_info.trade_fee, getTicker(my_side)) + getFiatText(curr_trade_info.trade_fee, getTicker(is_sell_form)) +")") ) font.pixelSize: tx_fee_text.font.pixelSize @@ -418,11 +418,11 @@ FloatingBackground { Layout.fillWidth: true Layout.leftMargin: 30 - button_type: my_side ? "danger" : "primary" + button_type: is_sell_form ? "danger" : "primary" width: 170 - text: API.get().empty_string + (my_side ? qsTr("Sell %1", "TICKER").arg(left_ticker) : qsTr("Buy %1", "TICKER").arg(left_ticker)) + text: API.get().empty_string + (is_sell_form ? qsTr("Sell %1", "TICKER").arg(left_ticker) : qsTr("Buy %1", "TICKER").arg(left_ticker)) enabled: valid_trade_info && !notEnoughBalanceForFees() && isValid() onClicked: confirm_trade_modal.open() } diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml index fc8b65674e..8948dcc8b7 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml @@ -24,8 +24,8 @@ ColumnLayout { id: price_header font.pixelSize: Style.textSizeSmall2 - text_value: API.get().empty_string + (is_asks ? qsTr("Ask Price") + "\n(" + selector_rel.ticker + ")": - qsTr("Bid Price") + "\n(" + selector_rel.ticker + ")") + text_value: API.get().empty_string + (is_asks ? qsTr("Ask Price") + "\n(" + right_ticker + ")": + qsTr("Bid Price") + "\n(" + right_ticker + ")") color: is_asks ? Style.colorRed : Style.colorGreen horizontalAlignment: is_asks ? Text.AlignLeft : Text.AlignRight @@ -50,7 +50,7 @@ ColumnLayout { font.pixelSize: price_header.font.pixelSize - text_value: API.get().empty_string + (qsTr("Quantity") + "\n(" + selector_base.ticker + ")") + text_value: API.get().empty_string + (qsTr("Quantity") + "\n(" + left_ticker + ")") color: Style.colorWhite1 anchors.verticalCenter: parent.verticalCenter } @@ -67,7 +67,7 @@ ColumnLayout { font.pixelSize: price_header.font.pixelSize - text_value: API.get().empty_string + (qsTr("Total") + "\n(" + selector_rel.ticker + ")") + text_value: API.get().empty_string + (qsTr("Total") + "\n(" + right_ticker + ")") color: Style.colorWhite1 anchors.verticalCenter: parent.verticalCenter } diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index 6e1628cc6c..569bcda079 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -193,7 +193,7 @@ Item { return [coin].concat(coins.filter(c => c.ticker !== ticker)) } - function getCoins(my_side) { + function getCoins(is_sell_form) { let coins = API.get().enabled_coins if(coins.length === 0) return coins @@ -203,10 +203,10 @@ Item { coins = moveToBeginning(coins, "KMD") // Return full list - if(my_side === undefined) return coins + if(is_sell_form === undefined) return coins // Filter for Sell - if(my_side) { + if(is_sell_form) { return coins.filter(c => { c.balance = API.get().get_balance(c.ticker) @@ -401,7 +401,7 @@ Item { anchors.right: parent.right anchors.top: parent.top - my_side: true + is_sell_form: true } // Receive From 01e0e4f8a31faa40427c9b2c5c066f618decf189 Mon Sep 17 00:00:00 2001 From: naezith Date: Sat, 8 Aug 2020 02:24:16 +0300 Subject: [PATCH 219/515] feat(gui): remove unused functions --- .../qml/Exchange/Trade/TickerSelector.qml | 16 -------- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 40 ------------------- 2 files changed, 56 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml b/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml index 0d68ab2911..21e0792897 100644 --- a/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml +++ b/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml @@ -17,22 +17,6 @@ RowLayout { property var ticker_list property string ticker - // Private - function getFilteredCoins() { - return getCoins(left_side) - } - - function getAnyAvailableCoin(filter_ticker) { - let coins = getFilteredCoins().map(c => c.ticker) - - // Filter out ticker - if(filter_ticker !== undefined || filter_ticker !== '') - coins = coins.filter(c => c !== filter_ticker) - - // Pick a random one if prioritized ones do not satisfy - return coins.length > 0 ? coins[0] : '' - } - DefaultImage { source: General.coinIcon(ticker) Layout.preferredWidth: 32 diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index 569bcda079..7745a7b50b 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -185,46 +185,6 @@ Item { setPair(true) } - function moveToBeginning(coins, ticker) { - const idx = coins.map(c => c.ticker).indexOf(ticker) - if(idx === -1) return - - const coin = coins[idx] - return [coin].concat(coins.filter(c => c.ticker !== ticker)) - } - - function getCoins(is_sell_form) { - let coins = API.get().enabled_coins - - if(coins.length === 0) return coins - - // Prioritize KMD / BTC pair by moving them to the start - coins = moveToBeginning(coins, "BTC") - coins = moveToBeginning(coins, "KMD") - - // Return full list - if(is_sell_form === undefined) return coins - - // Filter for Sell - if(is_sell_form) { - return coins.filter(c => { - c.balance = API.get().get_balance(c.ticker) - - return true - }) - } - // Filter for Receive - else { - return coins.filter(c => { - if(c.ticker === left_ticker) return false - - c.balance = API.get().get_balance(c.ticker) - - return true - }) - } - } - function getTicker(is_base) { return is_base ? left_ticker : right_ticker } From 8a4f14d69ddc9dbcbb904556fe6727dde989dcf7 Mon Sep 17 00:00:00 2001 From: naezith Date: Sat, 8 Aug 2020 02:36:08 +0300 Subject: [PATCH 220/515] feat(gui): fully remove getTicker --- atomic_qt_design/qml/Exchange/Trade/OrderForm.qml | 14 +++++++------- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 4 ---- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index f4caca231c..fe342c8eef 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -48,14 +48,14 @@ FloatingBackground { if(valid) valid = higherThanMinTradeAmount() if(valid) valid = !notEnoughBalance() - if(valid) valid = API.get().do_i_have_enough_funds(getTicker(is_sell_form), General.formatDouble(getNeededAmountToSpend(input_volume.field.text))) + if(valid) valid = API.get().do_i_have_enough_funds(base_ticker, General.formatDouble(getNeededAmountToSpend(input_volume.field.text))) if(valid && hasEthFees()) valid = hasEnoughEthForFees() return valid } function getMaxVolume() { - return API.get().get_balance(getTicker(is_sell_form)) + return API.get().get_balance(base_ticker) } function getMaxTradableVolume(set_as_current) { @@ -262,7 +262,7 @@ FloatingBackground { anchors.top: input_volume.bottom anchors.topMargin: 5 - text_value: getFiatText(input_volume.field.text, getTicker(is_sell_form)) + text_value: getFiatText(input_volume.field.text, base_ticker) font.pixelSize: input_volume.field.font.pixelSize CexInfoTrigger {} @@ -355,14 +355,14 @@ FloatingBackground { DefaultText { id: tx_fee_text - text_value: API.get().empty_string + ((qsTr('Transaction Fee') + ': ' + General.formatCrypto("", curr_trade_info.tx_fee, curr_trade_info.is_ticker_of_fees_eth ? "ETH" : getTicker(is_sell_form))) + + text_value: API.get().empty_string + ((qsTr('Transaction Fee') + ': ' + General.formatCrypto("", curr_trade_info.tx_fee, curr_trade_info.is_ticker_of_fees_eth ? "ETH" : base_ticker)) + // ETH Fees (hasEthFees() ? " + " + General.formatCrypto("", curr_trade_info.erc_fees, 'ETH') : '') + // Fiat part (" ("+ getFiatText(!hasEthFees() ? curr_trade_info.tx_fee : General.formatDouble((parseFloat(curr_trade_info.tx_fee) + parseFloat(curr_trade_info.erc_fees))), - curr_trade_info.is_ticker_of_fees_eth ? 'ETH' : getTicker(is_sell_form)) + curr_trade_info.is_ticker_of_fees_eth ? 'ETH' : base_ticker) +")") @@ -373,11 +373,11 @@ FloatingBackground { } DefaultText { - text_value: API.get().empty_string + (qsTr('Trading Fee') + ': ' + General.formatCrypto("", curr_trade_info.trade_fee, getTicker(is_sell_form)) + + text_value: API.get().empty_string + (qsTr('Trading Fee') + ': ' + General.formatCrypto("", curr_trade_info.trade_fee, base_ticker) + // Fiat part (" ("+ - getFiatText(curr_trade_info.trade_fee, getTicker(is_sell_form)) + getFiatText(curr_trade_info.trade_fee, base_ticker) +")") ) font.pixelSize: tx_fee_text.font.pixelSize diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index 7745a7b50b..3b9669cbe8 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -185,10 +185,6 @@ Item { setPair(true) } - function getTicker(is_base) { - return is_base ? left_ticker : right_ticker - } - function setPair(is_base, changed_ticker) { let base = left_ticker let rel = right_ticker From be482c901d68205ba64605027fd90c8abbda98d2 Mon Sep 17 00:00:00 2001 From: naezith Date: Sat, 8 Aug 2020 02:53:45 +0300 Subject: [PATCH 221/515] feat(gui): swap pair when same coin is selected at ticker lists --- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index 3b9669cbe8..81e4c8b4c9 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -189,14 +189,34 @@ Item { let base = left_ticker let rel = right_ticker + let is_swap = false // Set the new one if it's a change if(changed_ticker) { - if(is_base) base = changed_ticker - else rel = changed_ticker + if(is_base) { + // Check if it's a swap + if(base !== changed_ticker && rel === changed_ticker) + is_swap = true + + base = changed_ticker + } + else { + // Check if it's a swap + if(rel !== changed_ticker && base === changed_ticker) + is_swap = true + + rel = changed_ticker + } + } + + if(is_swap) { + console.log("Swapping current pair, it was: ", base, rel) + API.get().trading_pg.swap_market_pair() + } + else { + console.log("Setting current orderbook with params: ", base, rel) + API.get().trading_pg.set_current_orderbook(base, rel) } - console.log("Setting current orderbook with params: ", base, rel) - API.get().trading_pg.set_current_orderbook(base, rel) reset(true, is_base) updateTradeInfo() updateCexPrice(base, rel) From bd203c87577aca2ff68e4fcd5b69a10a1bdbf676 Mon Sep 17 00:00:00 2001 From: naezith Date: Sat, 8 Aug 2020 03:05:55 +0300 Subject: [PATCH 222/515] feat(gui): swap button functionality --- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index 81e4c8b4c9..97ec9a2880 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -185,14 +185,14 @@ Item { setPair(true) } - function setPair(is_base, changed_ticker) { + function setPair(is_left_side, changed_ticker) { let base = left_ticker let rel = right_ticker let is_swap = false // Set the new one if it's a change if(changed_ticker) { - if(is_base) { + if(is_left_side) { // Check if it's a swap if(base !== changed_ticker && rel === changed_ticker) is_swap = true @@ -217,7 +217,7 @@ Item { API.get().trading_pg.set_current_orderbook(base, rel) } - reset(true, is_base) + reset(true, is_left_side) updateTradeInfo() updateCexPrice(base, rel) exchange.onTradeTickerChanged(base) @@ -325,12 +325,18 @@ Item { Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter } + // Swap button DefaultImage { source: General.image_path + "trade_icon.svg" fillMode: Image.PreserveAspectFit Layout.preferredWidth: 16 Layout.preferredHeight: Layout.preferredWidth Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter + + MouseArea { + anchors.fill: parent + onClicked: setPair(true, right_ticker) + } } TickerSelector { From d1df7c9ddfda0551f27fa07ce284c44ca9379452 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Sat, 8 Aug 2020 07:50:51 +0200 Subject: [PATCH 223/515] feat(trading): fix crash --- src/atomic.dex.app.cpp | 2 -- src/atomic.dex.qt.market.pairs.cpp | 13 +++++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index f9215e8234..c3f0373a2b 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -718,8 +718,6 @@ namespace atomic_dex orders->removeRows(0, count, QModelIndex()); } orders->clear_registry(); - qobject_cast(m_manager_models.at("candlesticks"))->clear_data(); - qobject_cast(m_manager_models.at("orderbook"))->clear_orderbook(); //! Mark systems system_manager_.mark_system(); diff --git a/src/atomic.dex.qt.market.pairs.cpp b/src/atomic.dex.qt.market.pairs.cpp index 6da8ae90aa..efe11209dd 100644 --- a/src/atomic.dex.qt.market.pairs.cpp +++ b/src/atomic.dex.qt.market.pairs.cpp @@ -19,21 +19,26 @@ namespace atomic_dex { market_pairs::market_pairs(portfolio_model* portfolio_mdl, QObject* parent) : - QObject(parent), m_left_selection_box(new portfolio_proxy_model(portfolio_mdl)), m_right_selection_box(new portfolio_proxy_model(portfolio_mdl)) + QObject(parent), m_left_selection_box(new portfolio_proxy_model(nullptr)), m_right_selection_box(new portfolio_proxy_model(nullptr)) { // set_left_selected_coin("KMD"); m_left_selection_box->setSourceModel(portfolio_mdl); - //m_left_selection_box->setFilterRole(portfolio_model::Excluded); + // m_left_selection_box->setFilterRole(portfolio_model::Excluded); m_left_selection_box->setDynamicSortFilter(true); m_left_selection_box->sort_by_currency_balance(false); // set_right_selected_coin("BTC"); m_right_selection_box->setSourceModel(portfolio_mdl); - //m_right_selection_box->setFilterRole(portfolio_model::Excluded); + // m_right_selection_box->setFilterRole(portfolio_model::Excluded); m_right_selection_box->setDynamicSortFilter(true); m_right_selection_box->sort_by_currency_balance(false); } - market_pairs::~market_pairs() noexcept {} + + market_pairs::~market_pairs() noexcept + { + delete m_left_selection_box; + delete m_right_selection_box; + } } // namespace atomic_dex //! Properties implementation From 008c6280ee8c1df22ba7cc40c83ccb944b848e45 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Sat, 8 Aug 2020 07:53:52 +0200 Subject: [PATCH 224/515] feat(trading): add loging of creation/destruction of market pair --- src/atomic.dex.qt.market.pairs.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/atomic.dex.qt.market.pairs.cpp b/src/atomic.dex.qt.market.pairs.cpp index efe11209dd..f0ba5d1bf5 100644 --- a/src/atomic.dex.qt.market.pairs.cpp +++ b/src/atomic.dex.qt.market.pairs.cpp @@ -21,21 +21,21 @@ namespace atomic_dex market_pairs::market_pairs(portfolio_model* portfolio_mdl, QObject* parent) : QObject(parent), m_left_selection_box(new portfolio_proxy_model(nullptr)), m_right_selection_box(new portfolio_proxy_model(nullptr)) { - // set_left_selected_coin("KMD"); + spdlog::trace("{} l{} f[{}]", __FUNCTION__, __LINE__, fs::path(__FILE__).filename().string()); + spdlog::trace("market pairs model created"); m_left_selection_box->setSourceModel(portfolio_mdl); - // m_left_selection_box->setFilterRole(portfolio_model::Excluded); m_left_selection_box->setDynamicSortFilter(true); m_left_selection_box->sort_by_currency_balance(false); - // set_right_selected_coin("BTC"); m_right_selection_box->setSourceModel(portfolio_mdl); - // m_right_selection_box->setFilterRole(portfolio_model::Excluded); m_right_selection_box->setDynamicSortFilter(true); m_right_selection_box->sort_by_currency_balance(false); } market_pairs::~market_pairs() noexcept { + spdlog::trace("{} l{} f[{}]", __FUNCTION__, __LINE__, fs::path(__FILE__).filename().string()); + spdlog::trace("market pairs destroyed"); delete m_left_selection_box; delete m_right_selection_box; } From 4c356778eeb25d45b07dfb3b2a5e846154801bfa Mon Sep 17 00:00:00 2001 From: romanszterg Date: Sat, 8 Aug 2020 12:45:18 +0200 Subject: [PATCH 225/515] feat(trading): add a function to retrieve default value of dpow settings --- src/atomic.dex.mm2.cpp | 31 +++++++++++++++++++++--------- src/atomic.dex.mm2.hpp | 2 ++ src/atomic.dex.qt.trading.page.cpp | 10 ++++++++++ src/atomic.dex.qt.trading.page.hpp | 1 + src/atomic.dex.qt.utilities.cpp | 11 ++++++++++- src/atomic.dex.qt.utilities.hpp | 8 +++++--- 6 files changed, 50 insertions(+), 13 deletions(-) diff --git a/src/atomic.dex.mm2.cpp b/src/atomic.dex.mm2.cpp index 4e2690612e..d98150c780 100644 --- a/src/atomic.dex.mm2.cpp +++ b/src/atomic.dex.mm2.cpp @@ -829,15 +829,15 @@ namespace atomic_dex { tx_infos current_info{ - .am_i_sender = current.my_balance_change[0] == '-', - .confirmations = current.confirmations.has_value() ? current.confirmations.value() : 0, - .from = current.from, - .to = current.to, - .date = current.timestamp_as_date, - .timestamp = current.timestamp, - .tx_hash = current.tx_hash, - .fees = current.fee_details.normal_fees.has_value() ? current.fee_details.normal_fees.value().amount - : current.fee_details.erc_fees.value().total_fee, + .am_i_sender = current.my_balance_change[0] == '-', + .confirmations = current.confirmations.has_value() ? current.confirmations.value() : 0, + .from = current.from, + .to = current.to, + .date = current.timestamp_as_date, + .timestamp = current.timestamp, + .tx_hash = current.tx_hash, + .fees = current.fee_details.normal_fees.has_value() ? current.fee_details.normal_fees.value().amount + : current.fee_details.erc_fees.value().total_fee, .my_balance_change = current.my_balance_change, .total_amount = current.total_amount, .block_height = current.block_height, @@ -1126,4 +1126,17 @@ namespace atomic_dex { return this->m_orderbook_thread_active.load(); } + + nlohmann::json + mm2::get_raw_mm2_ticker_cfg(const std::string& ticker) const noexcept + { + nlohmann::json out; + if (m_mm2_raw_coins_cfg.find(ticker) != m_mm2_raw_coins_cfg.end()) + { + atomic_dex::coin_element element = m_mm2_raw_coins_cfg.at(ticker); + to_json(out, element); + return out; + } + return nlohmann::json::object(); + } } // namespace atomic_dex diff --git a/src/atomic.dex.mm2.hpp b/src/atomic.dex.mm2.hpp index f58abc032b..2ded366e1c 100644 --- a/src/atomic.dex.mm2.hpp +++ b/src/atomic.dex.mm2.hpp @@ -264,6 +264,8 @@ namespace atomic_dex [[nodiscard]] bool do_i_have_enough_funds(const std::string& ticker, const t_float_50& amount) const; [[nodiscard]] bool is_orderbook_thread_active() const noexcept; + + [[nodiscard]] nlohmann::json get_raw_mm2_ticker_cfg(const std::string& ticker) const noexcept; }; } // namespace atomic_dex diff --git a/src/atomic.dex.qt.trading.page.cpp b/src/atomic.dex.qt.trading.page.cpp index a4fa26a117..69cd01cdd2 100644 --- a/src/atomic.dex.qt.trading.page.cpp +++ b/src/atomic.dex.qt.trading.page.cpp @@ -18,6 +18,7 @@ #include "atomic.dex.qt.trading.page.hpp" #include "atomic.dex.mm2.hpp" #include "atomic.dex.provider.cex.prices.hpp" +#include "atomic.dex.qt.utilities.hpp" #include "atomic.threadpool.hpp" //! Consttructor / Destructor @@ -68,6 +69,15 @@ namespace atomic_dex //! Public QML API namespace atomic_dex { + QVariant + trading_page::get_raw_mm2_coin_cfg(const QString& ticker) const noexcept + { + QVariant out; + nlohmann::json j = m_system_manager.get_system().get_raw_mm2_ticker_cfg(ticker.toStdString()); + out = nlohmann_json_object_to_qt_json_object(j); + return out; + } + void trading_page::set_current_orderbook(const QString& base, const QString& rel) { diff --git a/src/atomic.dex.qt.trading.page.hpp b/src/atomic.dex.qt.trading.page.hpp index 1fecca5b68..c3c0c61213 100644 --- a/src/atomic.dex.qt.trading.page.hpp +++ b/src/atomic.dex.qt.trading.page.hpp @@ -105,6 +105,7 @@ namespace atomic_dex const QString& base, const QString& rel, const QString& price, const QString& volume, bool is_created_order, const QString& price_denom, const QString& price_numer, const QString& rel_nota = "", const QString& rel_confs = ""); Q_INVOKABLE void swap_market_pair(); + Q_INVOKABLE QVariant get_raw_mm2_coin_cfg(const QString& ticker) const noexcept; //! Properties [[nodiscard]] qt_orderbook_wrapper* get_orderbook_wrapper() const noexcept; diff --git a/src/atomic.dex.qt.utilities.cpp b/src/atomic.dex.qt.utilities.cpp index 4173593061..f0fd78b368 100644 --- a/src/atomic.dex.qt.utilities.cpp +++ b/src/atomic.dex.qt.utilities.cpp @@ -31,12 +31,21 @@ namespace atomic_dex QJsonArray nlohmann_json_array_to_qt_json_array(const nlohmann::json& j) { - QJsonArray out; + QJsonArray out; QJsonDocument q_json = QJsonDocument::fromJson(QString::fromStdString(j.dump()).toUtf8()); out = q_json.array(); return out; } + QJsonObject + nlohmann_json_object_to_qt_json_object(const json& j) + { + QJsonObject obj; + QJsonDocument q_json = QJsonDocument::fromJson(QString::fromStdString(j.dump()).toUtf8()); + obj = q_json.object(); + return obj; + } + QString retrieve_change_24h(const atomic_dex::coinpaprika_provider& paprika, const atomic_dex::coin_config& coin, const atomic_dex::cfg& config) { diff --git a/src/atomic.dex.qt.utilities.hpp b/src/atomic.dex.qt.utilities.hpp index 47c1f8496b..9a5a1bc531 100644 --- a/src/atomic.dex.qt.utilities.hpp +++ b/src/atomic.dex.qt.utilities.hpp @@ -16,6 +16,7 @@ #pragma once +#include #include #include @@ -27,7 +28,8 @@ namespace atomic_dex { - bool am_i_able_to_reach_this_endpoint(const QString& endpoint); - QJsonArray nlohmann_json_array_to_qt_json_array(const nlohmann::json& j); - QString retrieve_change_24h(const atomic_dex::coinpaprika_provider& paprika, const atomic_dex::coin_config& coin, const atomic_dex::cfg& config); + bool am_i_able_to_reach_this_endpoint(const QString& endpoint); + QJsonArray nlohmann_json_array_to_qt_json_array(const nlohmann::json& j); + QJsonObject nlohmann_json_object_to_qt_json_object(const nlohmann::json& j); + QString retrieve_change_24h(const atomic_dex::coinpaprika_provider& paprika, const atomic_dex::coin_config& coin, const atomic_dex::cfg& config); } // namespace atomic_dex \ No newline at end of file From a41116badba58a601cca52f77a0c2c4464496b2f Mon Sep 17 00:00:00 2001 From: naezith Date: Sat, 8 Aug 2020 17:31:55 +0300 Subject: [PATCH 226/515] feat(gui): display and use default trade config --- .../qml/Exchange/Trade/ConfirmTradeModal.qml | 8 ++++---- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 17 ++++++++++++++--- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml index ef53fe9042..9d4bc5aa78 100644 --- a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml +++ b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml @@ -93,8 +93,8 @@ DefaultModal { ColumnLayout { id: config_section - readonly property bool is_dpow_configurable: API.get().get_coin_info(rel_ticker).type === "Smart Chain" - + readonly property var default_config: API.get().trading_pg.get_raw_mm2_coin_cfg(rel_ticker) + readonly property bool is_dpow_configurable: config_section.default_config.requires_notarization Layout.bottomMargin: 10 Layout.alignment: Qt.AlignHCenter @@ -112,7 +112,7 @@ DefaultModal { Layout.alignment: Qt.AlignHCenter text_value: API.get().empty_string + ("✅ " + (config_section.is_dpow_configurable ? qsTr("dPoW protected") : - qsTr("%1 confirmations for incoming transactions").arg("WIP"))) + qsTr("%1 confirmations for incoming transactions").arg(config_section.default_config.required_confirmations))) } } @@ -239,7 +239,7 @@ DefaultModal { normal_configuration: { required_confirmation_count: required_confirmation_count.value }, - }) + }, config_section.default_config) root.close() } diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index 97ec9a2880..1f1cecefcb 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -223,12 +223,15 @@ Item { exchange.onTradeTickerChanged(base) } - function trade(base, rel, options) { + function trade(base, rel, options, default_config) { updateTradeInfo(true) // Force update trade info and cap the value for one last time + console.log("Trade config: ", JSON.stringify(options)) + console.log("Default config: ", JSON.stringify(default_config)) + let nota = "" let confs = "" - console.log("Trade config: ", JSON.stringify(options)) + if(options.enable_custom_config) { if(options.is_dpow_configurable) { nota = options.enable_dpow_confs ? "1" : "0" @@ -238,6 +241,15 @@ Item { confs = options.normal_configuration.required_confirmation_count.toString() } } + else { + if(default_config.requires_notarization !== undefined && default_config.requires_notarization !== null) { + nota = default_config.requires_notarization ? "1" : "0" + } + + if(nota !== "1") { + confs = default_config.required_confirmations.toString() + } + } const current_form = getCurrentForm() @@ -247,7 +259,6 @@ Item { const price_numer = preffered_order.price_numer const price = getCurrentPrice() const volume = current_form.field.text - console.log("QML place order: nota:", nota, ) console.log("QML place order: max balance:", current_form.getMaxVolume()) console.log("QML place order: params:", base, " <-> ", rel, " / price:", price, " / volume:", volume, " / is_created_order:", is_created_order, " / price_denom:", price_denom, " / price_numer:", price_numer, " / nota:", nota, " / confs:", confs) From b94724718d0e010f6bea6fd28f3fe3ebb37c82d0 Mon Sep 17 00:00:00 2001 From: milerius Date: Sun, 9 Aug 2020 08:21:45 +0200 Subject: [PATCH 227/515] feat(trading_combobox): live update balance on refresh --- src/atomic.dex.qt.portfolio.model.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/atomic.dex.qt.portfolio.model.cpp b/src/atomic.dex.qt.portfolio.model.cpp index eae1ab677c..729a87ad11 100644 --- a/src/atomic.dex.qt.portfolio.model.cpp +++ b/src/atomic.dex.qt.portfolio.model.cpp @@ -130,6 +130,8 @@ namespace atomic_dex update_value(MainCurrencyBalanceRole, main_currency_balance_value, idx, *this); const QString currency_price_for_one_unit = QString::fromStdString(paprika.get_rate_conversion(currency, ticker, ec, true)); update_value(MainCurrencyPriceForOneUnit, currency_price_for_one_unit, idx, *this); + const QString display = QString::fromStdString(ticker) + " (" + balance + ")"; + update_value(Display, display, idx, *this); } } From 7e6a8a954d0b557d720bd3802e653cef8a6af2d3 Mon Sep 17 00:00:00 2001 From: smk762 <35845239+smk762@users.noreply.github.com> Date: Sun, 9 Aug 2020 16:53:29 +0800 Subject: [PATCH 228/515] update gif slideshow --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 86cafc3afa..36137380d5 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ## [AtomicDEX](https://atomicdex.io) Desktop GUI application for Linux, MacOS and Windows. -[![atomicDEX mobile](https://s5.gifyu.com/images/dextop_optimize_bg.gif)](https://atomicdex.io) +[![atomicDEX mobile](https://i.imgur.com/kxkOQ5v.gif)](https://atomicdex.io) ## Get Started From d6be903228795685e6a67181171f42f616950a26 Mon Sep 17 00:00:00 2001 From: naezith Date: Sun, 9 Aug 2020 11:58:59 +0300 Subject: [PATCH 229/515] feat(gui): move notifications icon and panel to bottom left --- atomic_qt_design/qml/Screens/Dashboard.qml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/atomic_qt_design/qml/Screens/Dashboard.qml b/atomic_qt_design/qml/Screens/Dashboard.qml index 658481f2ad..fe4468578a 100644 --- a/atomic_qt_design/qml/Screens/Dashboard.qml +++ b/atomic_qt_design/qml/Screens/Dashboard.qml @@ -159,17 +159,17 @@ Item { id: notifications_panel width: 500 height: 500 - anchors.right: notifications_button.right - anchors.top: notifications_button.bottom - anchors.topMargin: 8 + anchors.left: sidebar.right + anchors.bottom: parent.bottom + anchors.bottomMargin: -40 } DefaultButton { id: notifications_button - anchors.top: parent.top - anchors.right: parent.right - anchors.topMargin: 8 - anchors.rightMargin: 8 + anchors.bottom: sidebar.bottom + anchors.bottomMargin: 150 + anchors.horizontalCenter: sidebar.horizontalCenter + anchors.horizontalCenterOffset: -sidebar.x*0.5 z: 1 text: "🔔" From 3adb4f70e09b0cc4cc56464e65c1af814042e381 Mon Sep 17 00:00:00 2001 From: naezith Date: Sun, 9 Aug 2020 12:01:49 +0300 Subject: [PATCH 230/515] feat(gui): remove pop test notification button --- .../qml/Dashboard/NotificationsPanel.qml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml index 153629d7e1..d6396f916c 100644 --- a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml +++ b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml @@ -238,16 +238,16 @@ FloatingBackground { RowLayout { - Layout.alignment: Qt.AlignBottom + Layout.alignment: Qt.AlignBottom | Qt.AlignRight Layout.bottomMargin: parent.spacing spacing: 10 - DefaultButton { - text: API.get().empty_string + (qsTr("Pop Test Notification")) - onClicked: { - onSwapStatusUpdated("ongoing", "finished", Date.now().toString(), "BTC", "KMD", "13.3.1337") - } - } +// DefaultButton { +// text: API.get().empty_string + (qsTr("Pop Test Notification")) +// onClicked: { +// onSwapStatusUpdated("ongoing", "finished", Date.now().toString(), "BTC", "KMD", "13.3.1337") +// } +// } DefaultButton { text: API.get().empty_string + (qsTr("Close")) From c6ecdf876041a28b09dded4075b80d9d8b532954 Mon Sep 17 00:00:00 2001 From: naezith Date: Sun, 9 Aug 2020 12:07:50 +0300 Subject: [PATCH 231/515] feat(gui): add margin to notifications list for the scrollbar --- .../qml/Dashboard/NotificationsPanel.qml | 14 +++++++------- atomic_qt_design/qml/Screens/Dashboard.qml | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml index d6396f916c..a41c1f217b 100644 --- a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml +++ b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml @@ -171,7 +171,7 @@ FloatingBackground { anchors.top: parent.top anchors.topMargin: 10 anchors.right: parent.right - anchors.rightMargin: 5 + anchors.rightMargin: 25 text_value: API.get().empty_string + (modelData.time) font.pixelSize: Style.textSizeSmall } @@ -242,12 +242,12 @@ FloatingBackground { Layout.bottomMargin: parent.spacing spacing: 10 -// DefaultButton { -// text: API.get().empty_string + (qsTr("Pop Test Notification")) -// onClicked: { -// onSwapStatusUpdated("ongoing", "finished", Date.now().toString(), "BTC", "KMD", "13.3.1337") -// } -// } + DefaultButton { + text: API.get().empty_string + (qsTr("Pop Test Notification")) + onClicked: { + onSwapStatusUpdated("ongoing", "finished", Date.now().toString(), "BTC", "KMD", "13.3.1337") + } + } DefaultButton { text: API.get().empty_string + (qsTr("Close")) diff --git a/atomic_qt_design/qml/Screens/Dashboard.qml b/atomic_qt_design/qml/Screens/Dashboard.qml index fe4468578a..ffab4d5eda 100644 --- a/atomic_qt_design/qml/Screens/Dashboard.qml +++ b/atomic_qt_design/qml/Screens/Dashboard.qml @@ -157,7 +157,7 @@ Item { NotificationsPanel { id: notifications_panel - width: 500 + width: 600 height: 500 anchors.left: sidebar.right anchors.bottom: parent.bottom From 6ec8c63a002c394e7fade34f8cab9fb7477baeab Mon Sep 17 00:00:00 2001 From: naezith Date: Sun, 9 Aug 2020 12:08:41 +0300 Subject: [PATCH 232/515] feat(gui): add margin to notifications list for the scrollbar --- .../qml/Dashboard/NotificationsPanel.qml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml index a41c1f217b..eb963d9ce8 100644 --- a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml +++ b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml @@ -212,7 +212,7 @@ FloatingBackground { anchors.bottom: parent.bottom anchors.bottomMargin: 5 anchors.right: parent.right - anchors.rightMargin: anchors.bottomMargin + anchors.rightMargin: anchors.bottomMargin + 20 color: Style.colorTheme1 @@ -242,12 +242,12 @@ FloatingBackground { Layout.bottomMargin: parent.spacing spacing: 10 - DefaultButton { - text: API.get().empty_string + (qsTr("Pop Test Notification")) - onClicked: { - onSwapStatusUpdated("ongoing", "finished", Date.now().toString(), "BTC", "KMD", "13.3.1337") - } - } +// DefaultButton { +// text: API.get().empty_string + (qsTr("Pop Test Notification")) +// onClicked: { +// onSwapStatusUpdated("ongoing", "finished", Date.now().toString(), "BTC", "KMD", "13.3.1337") +// } +// } DefaultButton { text: API.get().empty_string + (qsTr("Close")) From eeb6ce8903fe37835830abd577f08576cf7b30da Mon Sep 17 00:00:00 2001 From: naezith Date: Sun, 9 Aug 2020 12:16:17 +0300 Subject: [PATCH 233/515] feat(gui): change tray icon from komodo to atomicdex --- atomic_qt_design/assets/images/tray-icon.png | Bin 0 -> 5369 bytes .../qml/Dashboard/NotificationsPanel.qml | 2 +- qml.qrc | 1 + 3 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 atomic_qt_design/assets/images/tray-icon.png diff --git a/atomic_qt_design/assets/images/tray-icon.png b/atomic_qt_design/assets/images/tray-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..2a3c700735bafc32be5ee6c0adeaa90d3d4525c6 GIT binary patch literal 5369 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/assets/fonts/Montserrat-Light.ttf atomic_qt_design/assets/fonts/Montserrat-Thin.ttf atomic_qt_design/assets/fonts/Montserrat-Regular.ttf + atomic_qt_design/assets/images/tray-icon.png atomic_qt_design/assets/images/arrow_up.svg atomic_qt_design/assets/images/arrow_down.svg atomic_qt_design/assets/images/arrow-up.svg From 9c9b7c9240cd4edff083d4a80f5abdc7f78a27a8 Mon Sep 17 00:00:00 2001 From: naezith Date: Sun, 9 Aug 2020 12:21:45 +0300 Subject: [PATCH 234/515] feat(gui): use notification count instead of unread notifications count var --- atomic_qt_design/qml/Dashboard/NotificationsPanel.qml | 10 ---------- atomic_qt_design/qml/Screens/Dashboard.qml | 4 ++-- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml index 07245ac5eb..ea68d11a1f 100644 --- a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml +++ b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml @@ -9,7 +9,6 @@ import "../Components" FloatingBackground { id: root - property int unread_notification_count: 0 property var notifications_list: ([]) function reset() { @@ -24,10 +23,6 @@ FloatingBackground { visible: false - onVisibleChanged: { - if(visible) unread_notification_count = 0 - } - MouseArea { anchors.fill: parent preventStealing: true @@ -58,10 +53,6 @@ FloatingBackground { notifications_list = [obj].concat(notifications_list) } - // Update unread notification count - if(!root.visible) - ++unread_notification_count - // Display OS notification displayMessage(obj.title, obj.message) @@ -132,7 +123,6 @@ FloatingBackground { MouseArea { anchors.fill: parent onClicked: { - unread_notification_count = 0 notifications_list = [] } } diff --git a/atomic_qt_design/qml/Screens/Dashboard.qml b/atomic_qt_design/qml/Screens/Dashboard.qml index ffab4d5eda..aa02b4bf20 100644 --- a/atomic_qt_design/qml/Screens/Dashboard.qml +++ b/atomic_qt_design/qml/Screens/Dashboard.qml @@ -184,12 +184,12 @@ Item { anchors.horizontalCenter: parent.right anchors.verticalCenter: parent.bottom color: Style.colorRed - visible: notifications_panel.unread_notification_count > 0 + visible: notifications_panel.notifications_list.length > 0 DefaultText { id: count_text anchors.centerIn: parent - text_value: notifications_panel.unread_notification_count + text_value: notifications_panel.notifications_list.length font.pixelSize: Style.textSizeSmall1 font.bold: true color: Style.colorWhite9 From bde2d0aaff91110d633d3b2438efe8757213299d Mon Sep 17 00:00:00 2001 From: naezith Date: Sun, 9 Aug 2020 12:42:29 +0300 Subject: [PATCH 235/515] feat(gui): fix an undefined warning --- atomic_qt_design/qml/Dashboard/NotificationsPanel.qml | 2 +- atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml index ea68d11a1f..d3a359c078 100644 --- a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml +++ b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml @@ -114,7 +114,7 @@ FloatingBackground { DefaultText { id: mark_all_as_read - text_value: API.get().empty_string + (qsTr("Mark all as read") + " ✔️") + text_value: API.get().empty_string + (qsTr("Clear") + " ✔️") font.pixelSize: Style.textSizeSmall3 anchors.centerIn: parent color: Style.colorWhite10 diff --git a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml index 9d4bc5aa78..a52eb604ba 100644 --- a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml +++ b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml @@ -94,7 +94,7 @@ DefaultModal { id: config_section readonly property var default_config: API.get().trading_pg.get_raw_mm2_coin_cfg(rel_ticker) - readonly property bool is_dpow_configurable: config_section.default_config.requires_notarization + readonly property bool is_dpow_configurable: config_section.default_config.requires_notarization || false Layout.bottomMargin: 10 Layout.alignment: Qt.AlignHCenter From ebcc23b3e4720e19b0abe2f5725a29fdf5fa0fbb Mon Sep 17 00:00:00 2001 From: naezith Date: Sun, 9 Aug 2020 12:53:56 +0300 Subject: [PATCH 236/515] feat(gui): remove bell, move notifications button to app logo --- atomic_qt_design/qml/Screens/Dashboard.qml | 67 +++++++++++----------- atomic_qt_design/qml/Sidebar/Sidebar.qml | 3 + 2 files changed, 37 insertions(+), 33 deletions(-) diff --git a/atomic_qt_design/qml/Screens/Dashboard.qml b/atomic_qt_design/qml/Screens/Dashboard.qml index aa02b4bf20..493bcf9a69 100644 --- a/atomic_qt_design/qml/Screens/Dashboard.qml +++ b/atomic_qt_design/qml/Screens/Dashboard.qml @@ -155,6 +155,40 @@ Item { } } + Rectangle { + radius: 1337 + width: count_text.height * 1.5 + height: width + z: 1 + + Timer { + interval: 500 + running: true + repeat: true + onTriggered: { + console.log(sidebar.app_logo.x, sidebar.app_logo.y, sidebar.app_logo.width) + } + } + + x: sidebar.app_logo.x + sidebar.app_logo.width - 20 + y: sidebar.app_logo.y + color: notifications_panel.notifications_list.length > 0 ? Style.colorRed : Style.colorWhite7 + + DefaultText { + id: count_text + anchors.centerIn: parent + text_value: notifications_panel.notifications_list.length + font.pixelSize: Style.textSizeSmall1 + font.bold: true + color: notifications_panel.notifications_list.length > 0 ? Style.colorWhite9 : Style.colorWhite12 + } + + MouseArea { + anchors.fill: parent + onClicked: notifications_panel.visible = !notifications_panel.visible + } + } + NotificationsPanel { id: notifications_panel width: 600 @@ -164,39 +198,6 @@ Item { anchors.bottomMargin: -40 } - DefaultButton { - id: notifications_button - anchors.bottom: sidebar.bottom - anchors.bottomMargin: 150 - anchors.horizontalCenter: sidebar.horizontalCenter - anchors.horizontalCenterOffset: -sidebar.x*0.5 - - z: 1 - text: "🔔" - font.pixelSize: Style.textSizeSmall3 - minWidth: height - onClicked: notifications_panel.visible = !notifications_panel.visible - - Rectangle { - radius: 1337 - width: count_text.height * 1.5 - height: width - anchors.horizontalCenter: parent.right - anchors.verticalCenter: parent.bottom - color: Style.colorRed - visible: notifications_panel.notifications_list.length > 0 - - DefaultText { - id: count_text - anchors.centerIn: parent - text_value: notifications_panel.notifications_list.length - font.pixelSize: Style.textSizeSmall1 - font.bold: true - color: Style.colorWhite9 - } - } - } - DropShadow { anchors.fill: sidebar source: sidebar diff --git a/atomic_qt_design/qml/Sidebar/Sidebar.qml b/atomic_qt_design/qml/Sidebar/Sidebar.qml index 6175874e98..7cd30243ca 100644 --- a/atomic_qt_design/qml/Sidebar/Sidebar.qml +++ b/atomic_qt_design/qml/Sidebar/Sidebar.qml @@ -9,6 +9,8 @@ import "../Components" Item { id: sidebar + readonly property alias app_logo: app_logo + x: -top_rect.radius width: 200 - x height: parent.height @@ -119,6 +121,7 @@ Item { height: parent.height DefaultImage { + id: app_logo source: General.image_path + Style.sidebar_atomicdex_logo anchors.horizontalCenter: parent.horizontalCenter y: parent.width * 0.25 From 480dc193b8c7187571ba50dc1aa9c3f0f0601251 Mon Sep 17 00:00:00 2001 From: naezith Date: Sun, 9 Aug 2020 13:02:14 +0300 Subject: [PATCH 237/515] feat(gui): enable desktop notifications setting --- atomic_qt_design/qml/Constants/General.qml | 1 + atomic_qt_design/qml/Dashboard/NotificationsPanel.qml | 3 ++- atomic_qt_design/qml/Settings/Settings.qml | 9 ++++++++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/Constants/General.qml b/atomic_qt_design/qml/Constants/General.qml index 0da2f9480e..732e11b8bb 100644 --- a/atomic_qt_design/qml/Constants/General.qml +++ b/atomic_qt_design/qml/Constants/General.qml @@ -19,6 +19,7 @@ QtObject { readonly property string privacy_text: "*****" property bool privacy_mode: false + property bool enable_desktop_notifications: true readonly property int idx_dashboard_portfolio: 0 readonly property int idx_dashboard_wallet: 1 diff --git a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml index d3a359c078..9d219b1162 100644 --- a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml +++ b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml @@ -69,7 +69,8 @@ FloatingBackground { } function displayMessage(title, message) { - tray.showMessage(title, message) + if(General.enable_desktop_notifications) + tray.showMessage(title, message) } SystemTrayIcon { diff --git a/atomic_qt_design/qml/Settings/Settings.qml b/atomic_qt_design/qml/Settings/Settings.qml index 0fd5cb8469..cca1932085 100644 --- a/atomic_qt_design/qml/Settings/Settings.qml +++ b/atomic_qt_design/qml/Settings/Settings.qml @@ -66,6 +66,13 @@ Item { Layout.topMargin: 10 } + Switch { + Layout.alignment: Qt.AlignHCenter + text: API.get().empty_string + (qsTr("Enable Desktop Notifications")) + Component.onCompleted: checked = General.enable_desktop_notifications + onCheckedChanged: General.enable_desktop_notifications = checked + } + DefaultButton { Layout.fillWidth: true text: API.get().empty_string + (qsTr("Open Logs Folder")) @@ -128,7 +135,7 @@ Item { anchors.bottom: parent.bottom anchors.bottomMargin: 10 anchors.rightMargin: anchors.bottomMargin - text_value: API.get().empty_string + (qsTr("mm2 version") + ": " + mm2_version) + text_value: API.get().empty_string + (qsTr("mm2 version") + ": " + mm2_version) font.pixelSize: Style.textSizeSmall } } From 3ed9918329c18750bbaffadd97101cda2c3b247f Mon Sep 17 00:00:00 2001 From: naezith Date: Sun, 9 Aug 2020 16:57:54 +0300 Subject: [PATCH 238/515] feat(gui): move notifications panel to top --- atomic_qt_design/qml/Screens/Dashboard.qml | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/atomic_qt_design/qml/Screens/Dashboard.qml b/atomic_qt_design/qml/Screens/Dashboard.qml index 493bcf9a69..84ad3acea0 100644 --- a/atomic_qt_design/qml/Screens/Dashboard.qml +++ b/atomic_qt_design/qml/Screens/Dashboard.qml @@ -161,15 +161,6 @@ Item { height: width z: 1 - Timer { - interval: 500 - running: true - repeat: true - onTriggered: { - console.log(sidebar.app_logo.x, sidebar.app_logo.y, sidebar.app_logo.width) - } - } - x: sidebar.app_logo.x + sidebar.app_logo.width - 20 y: sidebar.app_logo.y color: notifications_panel.notifications_list.length > 0 ? Style.colorRed : Style.colorWhite7 @@ -194,8 +185,7 @@ Item { width: 600 height: 500 anchors.left: sidebar.right - anchors.bottom: parent.bottom - anchors.bottomMargin: -40 + anchors.top: parent.top } DropShadow { From 7674502dfb6295ac3ebfb0f23cb0bc47350c7ab9 Mon Sep 17 00:00:00 2001 From: naezith Date: Sun, 9 Aug 2020 16:59:19 +0300 Subject: [PATCH 239/515] feat(gui): atomicdex logo opens notifications panel --- atomic_qt_design/qml/Screens/Dashboard.qml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/atomic_qt_design/qml/Screens/Dashboard.qml b/atomic_qt_design/qml/Screens/Dashboard.qml index 84ad3acea0..4acf428ef9 100644 --- a/atomic_qt_design/qml/Screens/Dashboard.qml +++ b/atomic_qt_design/qml/Screens/Dashboard.qml @@ -155,6 +155,7 @@ Item { } } + // Unread notifications count Rectangle { radius: 1337 width: count_text.height * 1.5 @@ -173,11 +174,16 @@ Item { font.bold: true color: notifications_panel.notifications_list.length > 0 ? Style.colorWhite9 : Style.colorWhite12 } + } - MouseArea { - anchors.fill: parent - onClicked: notifications_panel.visible = !notifications_panel.visible - } + // Notifications panel button + MouseArea { + x: sidebar.app_logo.x + y: sidebar.app_logo.y + width: sidebar.app_logo.width + height: sidebar.app_logo.height + + onClicked: notifications_panel.visible = !notifications_panel.visible } NotificationsPanel { From 1ba88014e6821791de34b5a23af62bf39a841698 Mon Sep 17 00:00:00 2001 From: naezith Date: Sun, 9 Aug 2020 18:47:32 +0300 Subject: [PATCH 240/515] feat(gui): add read more about dPoW to default section too --- .../qml/Exchange/Trade/ConfirmTradeModal.qml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml index ef53fe9042..e9e72001c5 100644 --- a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml +++ b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml @@ -114,6 +114,17 @@ DefaultModal { (config_section.is_dpow_configurable ? qsTr("dPoW protected") : qsTr("%1 confirmations for incoming transactions").arg("WIP"))) } + + DefaultText { + visible: config_section.is_dpow_configurable + Layout.alignment: Qt.AlignHCenter + text_value: API.get().empty_string + (General.cex_icon + " " + qsTr('Read more about dPoW')) + wrapMode: Text.WordWrap + font.pixelSize: Style.textSizeSmall2 + + onLinkActivated: Qt.openUrlExternally(link) + linkColor: color + } } From 6091cad43a67fbec4ddea65e242c95d2230d0901 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Sun, 9 Aug 2020 17:54:12 +0200 Subject: [PATCH 241/515] feat(detail_swap_progress): add events array to the model data --- src/atomic.dex.qt.orders.data.hpp | 4 ++++ src/atomic.dex.qt.orders.model.cpp | 15 ++++++++++++--- src/atomic.dex.qt.orders.model.hpp | 5 +++-- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/atomic.dex.qt.orders.data.hpp b/src/atomic.dex.qt.orders.data.hpp index 29302dc897..864f25c112 100644 --- a/src/atomic.dex.qt.orders.data.hpp +++ b/src/atomic.dex.qt.orders.data.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include namespace atomic_dex { @@ -57,5 +58,8 @@ namespace atomic_dex //! Order error message QString order_error_message; + + //! Events + QJsonArray events; }; } // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.orders.model.cpp b/src/atomic.dex.qt.orders.model.cpp index 9d614db0d2..b2088bd3d9 100644 --- a/src/atomic.dex.qt.orders.model.cpp +++ b/src/atomic.dex.qt.orders.model.cpp @@ -18,6 +18,7 @@ #include "atomic.dex.qt.orders.model.hpp" #include "atomic.dex.mm2.hpp" #include "atomic.dex.qt.events.hpp" +#include "atomic.dex.qt.utilities.hpp" //! Utils namespace @@ -145,6 +146,8 @@ namespace atomic_dex item.order_error_state = value.toString(); case OrderErrorMessageRole: item.order_error_message = value.toString(); + case EventsRole: + item.events = value.toJsonArray(); } emit dataChanged(index, index, {role}); @@ -198,6 +201,8 @@ namespace atomic_dex return item.order_error_state; case OrderErrorMessageRole: return item.order_error_message; + case EventsRole: + return item.events; } return {}; } @@ -308,7 +313,8 @@ namespace atomic_dex .taker_payment_id = determine_payment_id(contents, is_maker, true), .is_swap = true, .is_cancellable = false, - .is_recoverable = contents.funds_recoverable}; + .is_recoverable = contents.funds_recoverable, + .events = nlohmann_json_array_to_qt_json_array(contents.events)}; data.ticker_pair = data.base_coin + "/" + data.rel_coin; if (data.order_status == "failed") { @@ -351,13 +357,15 @@ namespace atomic_dex { const QString& base_coin = data(idx, OrdersRoles::BaseCoinRole).toString(); const QString& rel_coin = data(idx, OrdersRoles::RelCoinRole).toString(); - m_dispatcher.trigger(QString::fromStdString(contents.uuid), prev_value.toString(), new_value.toString(), base_coin, rel_coin, new_value_d.toString()); + m_dispatcher.trigger( + QString::fromStdString(contents.uuid), prev_value.toString(), new_value.toString(), base_coin, rel_coin, new_value_d.toString()); } update_value(OrdersRoles::MakerPaymentIdRole, determine_payment_id(contents, is_maker, false), idx, *this); update_value(OrdersRoles::TakerPaymentIdRole, determine_payment_id(contents, is_maker, true), idx, *this); auto [state, msg] = extract_error(contents); update_value(OrdersRoles::OrderErrorStateRole, state, idx, *this); update_value(OrdersRoles::OrderErrorMessageRole, msg, idx, *this); + update_value(OrdersRoles::EventsRole, nlohmann_json_array_to_qt_json_array(contents.events), idx, *this); emit lengthChanged(); } else @@ -507,7 +515,8 @@ namespace atomic_dex {CancellableRole, "cancellable"}, {IsRecoverableRole, "recoverable"}, {OrderErrorStateRole, "order_error_state"}, - {OrderErrorMessageRole, "order_error_message"}}; + {OrderErrorMessageRole, "order_error_message"}, + {EventsRole, "events"}}; } int diff --git a/src/atomic.dex.qt.orders.model.hpp b/src/atomic.dex.qt.orders.model.hpp index 4a85c190eb..71472336fb 100644 --- a/src/atomic.dex.qt.orders.model.hpp +++ b/src/atomic.dex.qt.orders.model.hpp @@ -56,7 +56,8 @@ namespace atomic_dex CancellableRole, IsRecoverableRole, OrderErrorStateRole, - OrderErrorMessageRole + OrderErrorMessageRole, + EventsRole }; @@ -82,7 +83,7 @@ namespace atomic_dex private: ag::ecs::system_manager& m_system_manager; - entt::dispatcher& m_dispatcher; + entt::dispatcher& m_dispatcher; using t_orders_datas = QVector; using t_orders_id_registry = std::unordered_set; From a1fb691a5a8eb46f0110d18abb3006f7a920c7a7 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Sun, 9 Aug 2020 18:08:52 +0200 Subject: [PATCH 242/515] feat(settings): add basis for settings page abstraction --- CMakeLists.txt | 1 + src/atomic.dex.qt.settings.page.cpp | 32 ++++++++++++++++++++++ src/atomic.dex.qt.settings.page.hpp | 41 +++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 src/atomic.dex.qt.settings.page.cpp create mode 100644 src/atomic.dex.qt.settings.page.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ee50bde95..e07b118428 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -164,6 +164,7 @@ target_sources(atomic_qt_shared_deps INTERFACE ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.contact.model.cpp ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.trading.page.cpp ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.market.pairs.cpp + ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.settings.page.cpp ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.orderbook.cpp ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.orderbook.model.cpp ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.orderbook.proxy.model.cpp diff --git a/src/atomic.dex.qt.settings.page.cpp b/src/atomic.dex.qt.settings.page.cpp new file mode 100644 index 0000000000..92773d57c2 --- /dev/null +++ b/src/atomic.dex.qt.settings.page.cpp @@ -0,0 +1,32 @@ +/****************************************************************************** + * Copyright © 2013-2019 The Komodo Platform Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * Komodo Platform software, including this file may be copied, modified, * + * propagated or distributed except according to the terms contained in the * + * LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + +#include "atomic.dex.qt.settings.page.hpp" + +//! Constructo destructor +namespace atomic_dex +{ + settings_page::settings_page(entt::registry& registry, QObject* parent) noexcept : QObject(parent), system(registry) {} +} // namespace atomic_dex + +//! Override +namespace atomic_dex +{ + void + settings_page::update() noexcept + { + } +} // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.settings.page.hpp b/src/atomic.dex.qt.settings.page.hpp new file mode 100644 index 0000000000..360335ff26 --- /dev/null +++ b/src/atomic.dex.qt.settings.page.hpp @@ -0,0 +1,41 @@ +/****************************************************************************** + * Copyright © 2013-2019 The Komodo Platform Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * Komodo Platform software, including this file may be copied, modified, * + * propagated or distributed except according to the terms contained in the * + * LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + +#pragma once + +//! QT +#include + +//! PCH +#include "atomic.dex.pch.hpp" + +namespace atomic_dex +{ + class settings_page final : public QObject, public ag::ecs::pre_update_system + { + //! Q_Object definition + Q_OBJECT + + public: + explicit settings_page(entt::registry& registry, QObject* parent = nullptr) noexcept; + ~settings_page() noexcept final = default; + + //! Public override + void update() noexcept final; + }; +} // namespace atomic_dex + +REFL_AUTO(type(atomic_dex::settings_page)) \ No newline at end of file From b7f9bea17ffaa4e395581ce8d8762cde16a70051 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Sun, 9 Aug 2020 19:24:05 +0200 Subject: [PATCH 243/515] feat(settings): add page abstraction --- .../assets/languages/atomic_qt_en.ts | 126 +++++++++----- .../assets/languages/atomic_qt_fr.ts | 117 ++++++++----- .../assets/languages/atomic_qt_tr.ts | 117 ++++++++----- .../qml/Components/CopyFieldButton.qml | 2 +- atomic_qt_design/qml/Components/EulaModal.qml | 12 +- .../qml/Components/PasswordField.qml | 16 +- .../qml/Components/PasswordForm.qml | 4 +- .../qml/Components/RightClickMenu.qml | 6 +- .../qml/Components/TextFieldWithTitle.qml | 2 +- .../qml/Components/UpdateModal.qml | 8 +- .../qml/Components/UpdateNotificationLine.qml | 2 +- .../qml/Components/WalletNameField.qml | 4 +- atomic_qt_design/qml/Constants/General.qml | 2 +- .../qml/Dashboard/NotificationsPanel.qml | 18 +- atomic_qt_design/qml/Exchange/Exchange.qml | 6 +- .../qml/Exchange/History/History.qml | 4 +- .../qml/Exchange/History/SwapList.qml | 4 +- .../qml/Exchange/OrderContent.qml | 16 +- atomic_qt_design/qml/Exchange/OrderModal.qml | 38 ++--- .../qml/Exchange/Orders/OrderList.qml | 4 +- .../qml/Exchange/Orders/Orders.qml | 6 +- .../qml/Exchange/Trade/CandleStickChart.qml | 2 +- .../qml/Exchange/Trade/ConfirmTradeModal.qml | 26 +-- .../qml/Exchange/Trade/OrderForm.qml | 28 ++-- .../qml/Exchange/Trade/OrderbookSection.qml | 12 +- .../qml/Exchange/Trade/PriceLine.qml | 20 +-- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 2 +- atomic_qt_design/qml/NoConnection.qml | 8 +- atomic_qt_design/qml/Portfolio/Portfolio.qml | 34 ++-- atomic_qt_design/qml/Screens/Dashboard.qml | 8 +- atomic_qt_design/qml/Screens/FirstLaunch.qml | 10 +- .../qml/Screens/InitialLoading.qml | 4 +- atomic_qt_design/qml/Screens/Login.qml | 10 +- atomic_qt_design/qml/Screens/NewUser.qml | 36 ++-- atomic_qt_design/qml/Screens/RecoverSeed.qml | 20 +-- .../qml/Settings/DeleteWalletModal.qml | 14 +- atomic_qt_design/qml/Settings/Languages.qml | 8 +- .../qml/Settings/RecoverSeedModal.qml | 12 +- atomic_qt_design/qml/Settings/Settings.qml | 24 +-- atomic_qt_design/qml/Sidebar/Sidebar.qml | 2 +- .../qml/Sidebar/SidebarBottom.qml | 6 +- .../qml/Sidebar/SidebarCenter.qml | 10 +- atomic_qt_design/qml/Wallet/AddressBook.qml | 16 +- atomic_qt_design/qml/Wallet/AddressList.qml | 2 +- .../qml/Wallet/ClaimRewardsModal.qml | 8 +- atomic_qt_design/qml/Wallet/CoinList.qml | 2 +- .../qml/Wallet/EnableCoinModal.qml | 16 +- atomic_qt_design/qml/Wallet/Main.qml | 40 ++--- atomic_qt_design/qml/Wallet/ReceiveModal.qml | 8 +- atomic_qt_design/qml/Wallet/SendModal.qml | 64 +++---- atomic_qt_design/qml/Wallet/SendResult.qml | 22 +-- atomic_qt_design/qml/Wallet/Sidebar.qml | 8 +- .../qml/Wallet/TransactionDetailsModal.qml | 34 ++-- atomic_qt_design/qml/Wallet/Transactions.qml | 10 +- atomic_qt_design/qml/main.qml | 2 +- src/atomic.dex.app.cpp | 131 +++++---------- src/atomic.dex.app.hpp | 94 +++++------ src/atomic.dex.cfg.cpp | 7 +- src/atomic.dex.events.hpp | 1 + src/atomic.dex.qt.portfolio.model.cpp | 28 +++- src/atomic.dex.qt.portfolio.model.hpp | 11 +- src/atomic.dex.qt.settings.page.cpp | 157 +++++++++++++++++- src/atomic.dex.qt.settings.page.hpp | 51 +++++- 63 files changed, 906 insertions(+), 616 deletions(-) diff --git a/atomic_qt_design/assets/languages/atomic_qt_en.ts b/atomic_qt_design/assets/languages/atomic_qt_en.ts index 9d28c02d8b..975485149a 100644 --- a/atomic_qt_design/assets/languages/atomic_qt_en.ts +++ b/atomic_qt_design/assets/languages/atomic_qt_en.ts @@ -95,42 +95,58 @@ - - Enable Komodo dPoW security + + Security configuration - - Enable Notarization + + dPoW protected - - Change required confirmations + + %1 confirmations for incoming transactions - - Confirmations + + Use custom protection settings for incoming %1 transactions + TICKER - - Recommended + + Enable Komodo dPoW security - - Warning, this atomic swap is not dPoW/blockchain confirmation protected + + <a href="https://komodoplatform.com/security-delayed-proof-of-work-dpow/">Read more about dPoW</a> - - Cancel + + Warning, this atomic swap is not dPoW protected! + Change required confirmations + + + + + Confirmations + + + + + Cancel + + + + Confirm @@ -146,22 +162,22 @@ Dashboard - + News - + Dapps - + CEX Data - + Markets data (prices, charts, etc.) marked with the ⓘ icon originates from third party sources. (<a href="https://coinpaprika.com">coinpaprika.com</a>) @@ -645,6 +661,39 @@ + + NotificationsPanel + + + Swap status updated + + + + + AtomicDEX Pro + + + + + Notifications + + + + + Clear + + + + + There isn't any notification + + + + + Close + + + OrderContent @@ -1358,31 +1407,36 @@ + Enable Desktop Notifications + + + + Open Logs Folder - + View Seed - + Disclaimer and ToS - + Delete Wallet - + Log out - + mm2 version @@ -1464,53 +1518,43 @@ Trade - - No balance available - - - - - Please enable a coin with balance or deposit funds - - - - + Placed the order - + Failed to place the order - + Please fill the price field - + %1 balance is lower than minimum trade amount - + Not enough balance for the fees. Need at least %1 more AMT TICKER - + Please fill the volume field - + Not enough ETH for the transaction fee - + Amount is lower than minimum trade amount diff --git a/atomic_qt_design/assets/languages/atomic_qt_fr.ts b/atomic_qt_design/assets/languages/atomic_qt_fr.ts index 5b2370a51e..af182082d7 100644 --- a/atomic_qt_design/assets/languages/atomic_qt_fr.ts +++ b/atomic_qt_design/assets/languages/atomic_qt_fr.ts @@ -102,42 +102,58 @@ Cette transaction peut prendre jusqu'à 10 mins - NE fermez pas l'application ! - - Enable Komodo dPoW security + + Security configuration - - Enable Notarization + + dPoW protected - - Change required confirmations + + %1 confirmations for incoming transactions - - Confirmations - Confirmations + + Use custom protection settings for incoming %1 transactions + TICKER + - - Recommended + + Enable Komodo dPoW security + + + + + <a href="https://komodoplatform.com/security-delayed-proof-of-work-dpow/">Read more about dPoW</a> - - Warning, this atomic swap is not dPoW/blockchain confirmation protected + + Warning, this atomic swap is not dPoW protected! - + + Change required confirmations + + + + + Confirmations + Confirmations + + + Cancel Annuler - + Confirm Confirmer @@ -153,22 +169,22 @@ Dashboard - + News Actualités - + Dapps - + CEX Data - + Markets data (prices, charts, etc.) marked with the ⓘ icon originates from third party sources. (<a href="https://coinpaprika.com">coinpaprika.com</a>) @@ -667,12 +683,34 @@ NotificationsPanel + + Swap status updated + + + + AtomicDEX Pro - AtomicDEX Pro + AtomicDEX Pro + + + + Notifications + + + Clear + + + + + There isn't any notification + + + + Close - Fermer + Fermer @@ -1524,31 +1562,36 @@ + Enable Desktop Notifications + + + + Open Logs Folder Ouvrir le répertoire de logs - + View Seed Voir la phrase de récupération - + Disclaimer and ToS Clause de non-responsabilité et conditions d'utilisation - + Delete Wallet Supprimez le portefeuille - + Log out Déconnection - + mm2 version Version de mm2 @@ -1654,14 +1697,12 @@ Trade - No balance available - Aucun solde disponible + Aucun solde disponible - Please enable a coin with balance or deposit funds - Veuillez activer une pièce avec solde ou déposez des fonds + Veuillez activer une pièce avec solde ou déposez des fonds Trade @@ -1672,43 +1713,43 @@ Impossible de placer l'ordre. - + Placed the order - + Failed to place the order - + Please fill the price field - + %1 balance is lower than minimum trade amount - + Not enough balance for the fees. Need at least %1 more AMT TICKER - + Please fill the volume field - + Not enough ETH for the transaction fee Pas assez d'ETH pour les frais de transaction - + Amount is lower than minimum trade amount diff --git a/atomic_qt_design/assets/languages/atomic_qt_tr.ts b/atomic_qt_design/assets/languages/atomic_qt_tr.ts index c8439ea929..5f4869aa10 100644 --- a/atomic_qt_design/assets/languages/atomic_qt_tr.ts +++ b/atomic_qt_design/assets/languages/atomic_qt_tr.ts @@ -106,42 +106,58 @@ Bu işlem 10 dakika kadar sürebilir - Programı KAPATMAYINIZ! - - Enable Komodo dPoW security + + Security configuration - - Enable Notarization + + dPoW protected - - Change required confirmations + + %1 confirmations for incoming transactions - - Confirmations - Onay Sayısı + + Use custom protection settings for incoming %1 transactions + TICKER + - - Recommended + + Enable Komodo dPoW security + + + + + <a href="https://komodoplatform.com/security-delayed-proof-of-work-dpow/">Read more about dPoW</a> - - Warning, this atomic swap is not dPoW/blockchain confirmation protected + + Warning, this atomic swap is not dPoW protected! - + + Change required confirmations + + + + + Confirmations + Onay Sayısı + + + Cancel İptal - + Confirm Onayla @@ -157,22 +173,22 @@ Dashboard - + News Haberler - + Dapps - + CEX Data - + Markets data (prices, charts, etc.) marked with the ⓘ icon originates from third party sources. (<a href="https://coinpaprika.com">coinpaprika.com</a>) @@ -669,12 +685,34 @@ NotificationsPanel + + Swap status updated + + + + AtomicDEX Pro - AtomıcDEX Pro + AtomıcDEX Pro + + + + Notifications + + + Clear + + + + + There isn't any notification + + + + Close - Kapat + Kapat @@ -1525,21 +1563,26 @@ + Enable Desktop Notifications + + + + Open Logs Folder Log Klasörünü Aç - + View Seed Seed'i Gör - + Disclaimer and ToS Sorumluluk Reddi ve K.Ş. - + mm2 version mm2 versiyonu @@ -1548,12 +1591,12 @@ Dil - + Delete Wallet Cüzdanı Sil - + Log out Çıkış @@ -1659,57 +1702,55 @@ Trade - No balance available - Bakiye yok + Bakiye yok - Please enable a coin with balance or deposit funds - Lütfen bakiyeniz bulunan bir kriptopara etkinleştirin ya da mevcut bakiyenizi doldurun + Lütfen bakiyeniz bulunan bir kriptopara etkinleştirin ya da mevcut bakiyenizi doldurun Trade Al-Sat - + Placed the order - + Failed to place the order - + Please fill the price field - + %1 balance is lower than minimum trade amount - + Not enough balance for the fees. Need at least %1 more AMT TICKER - + Please fill the volume field - + Not enough ETH for the transaction fee - + Amount is lower than minimum trade amount diff --git a/atomic_qt_design/qml/Components/CopyFieldButton.qml b/atomic_qt_design/qml/Components/CopyFieldButton.qml index 4548784a35..9ed87aaa57 100644 --- a/atomic_qt_design/qml/Components/CopyFieldButton.qml +++ b/atomic_qt_design/qml/Components/CopyFieldButton.qml @@ -19,7 +19,7 @@ DefaultImage { onClicked: () => { input_field.selectAll() input_field.copy() - toast.show(API.get().empty_string + (qsTr("Copied to Clipboard")), General.time_toast_basic_info, "", false) + toast.show(API.get().settings_pg.empty_string + (qsTr("Copied to Clipboard")), General.time_toast_basic_info, "", false) } } } diff --git a/atomic_qt_design/qml/Components/EulaModal.qml b/atomic_qt_design/qml/Components/EulaModal.qml index f9e3289dc7..f0307c9f11 100644 --- a/atomic_qt_design/qml/Components/EulaModal.qml +++ b/atomic_qt_design/qml/Components/EulaModal.qml @@ -26,7 +26,7 @@ DefaultModal { width: parent.width ModalHeader { - title: API.get().empty_string + (qsTr("Disclaimer & Terms of Service")) + title: API.get().settings_pg.empty_string + (qsTr("Disclaimer & Terms of Service")) } @@ -45,7 +45,7 @@ DefaultModal { DefaultText { id: eula_text - text_value: API.get().empty_string + (getEula()) + text_value: API.get().settings_pg.empty_string + (getEula()) width: eula_rect.width - 40 } @@ -56,26 +56,26 @@ DefaultModal { DefaultCheckBox { id: accept_eula visible: !close_only - text: API.get().empty_string + (qsTr("Accept EULA")) + text: API.get().settings_pg.empty_string + (qsTr("Accept EULA")) } DefaultCheckBox { id: accept_tac visible: !close_only - text: API.get().empty_string + (qsTr("Accept Terms and Conditions")) + text: API.get().settings_pg.empty_string + (qsTr("Accept Terms and Conditions")) } // Buttons RowLayout { DefaultButton { - text: API.get().empty_string + (close_only ? qsTr("Close") : qsTr("Cancel")) + text: API.get().settings_pg.empty_string + (close_only ? qsTr("Close") : qsTr("Cancel")) Layout.fillWidth: true onClicked: root.close() } PrimaryButton { visible: !close_only - text: API.get().empty_string + (qsTr("Confirm")) + text: API.get().settings_pg.empty_string + (qsTr("Confirm")) Layout.fillWidth: true enabled: accept_eula.checked && accept_tac.checked onClicked: { diff --git a/atomic_qt_design/qml/Components/PasswordField.qml b/atomic_qt_design/qml/Components/PasswordField.qml index cc13e53d85..42b7e0c920 100644 --- a/atomic_qt_design/qml/Components/PasswordField.qml +++ b/atomic_qt_design/qml/Components/PasswordField.qml @@ -50,8 +50,8 @@ ColumnLayout { TextFieldWithTitle { id: pw hidable: true - title: API.get().empty_string + (qsTr("Password")) - field.placeholderText: API.get().empty_string + (new_password ? qsTr("Enter a password for your wallet") : qsTr("Enter the password of your wallet")) + title: API.get().settings_pg.empty_string + (qsTr("Password")) + field.placeholderText: API.get().settings_pg.empty_string + (new_password ? qsTr("Enter a password for your wallet") : qsTr("Enter the password of your wallet")) field.validator: RegExpValidator { regExp: General.reg_pass_input } } @@ -63,32 +63,32 @@ ColumnLayout { DefaultText { font.pixelSize: Style.textSizeSmall3 - text_value: API.get().empty_string + (hintPrefix(hasEnoughLowercaseCharacters()) + qsTr("At least 1 lowercase alphabetical character")) + text_value: API.get().settings_pg.empty_string + (hintPrefix(hasEnoughLowercaseCharacters()) + qsTr("At least 1 lowercase alphabetical character")) color: hintColor(hasEnoughLowercaseCharacters()) } DefaultText { font.pixelSize: Style.textSizeSmall3 - text_value: API.get().empty_string + (hintPrefix(hasEnoughUppercaseCharacters()) + qsTr("At least 1 uppercase alphabetical character")) + text_value: API.get().settings_pg.empty_string + (hintPrefix(hasEnoughUppercaseCharacters()) + qsTr("At least 1 uppercase alphabetical character")) color: hintColor(hasEnoughUppercaseCharacters()) } DefaultText { font.pixelSize: Style.textSizeSmall3 - text_value: API.get().empty_string + (hintPrefix(hasEnoughNumericCharacters()) + qsTr("At least 1 numeric character")) + text_value: API.get().settings_pg.empty_string + (hintPrefix(hasEnoughNumericCharacters()) + qsTr("At least 1 numeric character")) color: hintColor(hasEnoughNumericCharacters()) } DefaultText { font.pixelSize: Style.textSizeSmall3 - text_value: API.get().empty_string + (hintPrefix(hasEnoughSpecialCharacters()) + qsTr("At least 1 special character (eg. !@#$%)")) + text_value: API.get().settings_pg.empty_string + (hintPrefix(hasEnoughSpecialCharacters()) + qsTr("At least 1 special character (eg. !@#$%)")) color: hintColor(hasEnoughSpecialCharacters()) } DefaultText { font.pixelSize: Style.textSizeSmall3 - text_value: API.get().empty_string + (hintPrefix(hasEnoughCharacters()) + qsTr("At least 16 characters")) + text_value: API.get().settings_pg.empty_string + (hintPrefix(hasEnoughCharacters()) + qsTr("At least 16 characters")) color: hintColor(hasEnoughCharacters()) } DefaultText { font.pixelSize: Style.textSizeSmall3 - text_value: API.get().empty_string + (hintPrefix(passwordsDoMatch()) + qsTr("Password and Confirm Password have to be same")) + text_value: API.get().settings_pg.empty_string + (hintPrefix(passwordsDoMatch()) + qsTr("Password and Confirm Password have to be same")) color: hintColor(passwordsDoMatch()) } } diff --git a/atomic_qt_design/qml/Components/PasswordForm.qml b/atomic_qt_design/qml/Components/PasswordForm.qml index a2345657d1..0513f742f6 100644 --- a/atomic_qt_design/qml/Components/PasswordForm.qml +++ b/atomic_qt_design/qml/Components/PasswordForm.qml @@ -39,8 +39,8 @@ ColumnLayout { hide_hint: true visible: confirm id: input_confirm_password - title: API.get().empty_string + (qsTr("Confirm Password")) - field.placeholderText: API.get().empty_string + (qsTr("Enter the same password to confirm")) + title: API.get().settings_pg.empty_string + (qsTr("Confirm Password")) + field.placeholderText: API.get().settings_pg.empty_string + (qsTr("Enter the same password to confirm")) } } diff --git a/atomic_qt_design/qml/Components/RightClickMenu.qml b/atomic_qt_design/qml/Components/RightClickMenu.qml index db86310fe6..657523a6d4 100644 --- a/atomic_qt_design/qml/Components/RightClickMenu.qml +++ b/atomic_qt_design/qml/Components/RightClickMenu.qml @@ -24,17 +24,17 @@ MouseArea { id: contextMenu MenuItem { - text: API.get().empty_string + (qsTr("Cut")) + text: API.get().settings_pg.empty_string + (qsTr("Cut")) enabled: !text_field.readOnly && text_field.selectedText.length > 0 && text_field.echoMode !== TextInput.Password onTriggered: text_field.cut() } MenuItem { - text: API.get().empty_string + (qsTr("Copy")) + text: API.get().settings_pg.empty_string + (qsTr("Copy")) enabled: text_field.selectedText.length > 0 && text_field.echoMode !== TextInput.Password onTriggered: text_field.copy() } MenuItem { - text: API.get().empty_string + (qsTr("Paste")) + text: API.get().settings_pg.empty_string + (qsTr("Paste")) enabled: !text_field.readOnly onTriggered: text_field.paste() } diff --git a/atomic_qt_design/qml/Components/TextFieldWithTitle.qml b/atomic_qt_design/qml/Components/TextFieldWithTitle.qml index 57f8125201..162dfd6d33 100644 --- a/atomic_qt_design/qml/Components/TextFieldWithTitle.qml +++ b/atomic_qt_design/qml/Components/TextFieldWithTitle.qml @@ -29,7 +29,7 @@ ColumnLayout { DefaultText { visible: required && input_field.text === '' font.pixelSize: Style.textSizeSmall2 - text_value: API.get().empty_string + (qsTr("Required")) + text_value: API.get().settings_pg.empty_string + (qsTr("Required")) color: Style.colorRed } } diff --git a/atomic_qt_design/qml/Components/UpdateModal.qml b/atomic_qt_design/qml/Components/UpdateModal.qml index d17081cd0f..a4e5610b46 100644 --- a/atomic_qt_design/qml/Components/UpdateModal.qml +++ b/atomic_qt_design/qml/Components/UpdateModal.qml @@ -34,7 +34,7 @@ DefaultModal { font.pixelSize: Style.textSize2 - text_value: API.get().empty_string + ("(" + (!suggest_update ? qsTr("Available") : required_update ? qsTr("Required") : qsTr("Recommended")) + ")") + text_value: API.get().settings_pg.empty_string + ("(" + (!suggest_update ? qsTr("Available") : required_update ? qsTr("Required") : qsTr("Recommended")) + ")") color: !suggest_update ? Style.colorGreen : required_update ? Style.colorRed : Style.colorOrange } @@ -43,7 +43,7 @@ DefaultModal { ModalHeader { id: header - title: API.get().empty_string + (General.download_icon + " " + qsTr("New Update!") + " " + (API.get().update_status.current_version + " " + General.right_arrow_icon + " " + API.get().update_status.new_version)) + title: API.get().settings_pg.empty_string + (General.download_icon + " " + qsTr("New Update!") + " " + (API.get().update_status.current_version + " " + General.right_arrow_icon + " " + API.get().update_status.new_version)) } @@ -69,14 +69,14 @@ DefaultModal { Layout.alignment: Qt.AlignHCenter DefaultButton { - text: API.get().empty_string + (qsTr("Skip")) + text: API.get().settings_pg.empty_string + (qsTr("Skip")) onClicked: root.close() visible: !required_update } PrimaryButton { enabled: status_good - text: API.get().empty_string + (qsTr("Download")) + text: API.get().settings_pg.empty_string + (qsTr("Download")) onClicked: Qt.openUrlExternally(API.get().update_status.download_url) } } diff --git a/atomic_qt_design/qml/Components/UpdateNotificationLine.qml b/atomic_qt_design/qml/Components/UpdateNotificationLine.qml index ada0f7e31e..8cf79aa5f9 100644 --- a/atomic_qt_design/qml/Components/UpdateNotificationLine.qml +++ b/atomic_qt_design/qml/Components/UpdateNotificationLine.qml @@ -22,7 +22,7 @@ Rectangle { anchors.horizontalCenterOffset: -parent.radius * 0.5 anchors.verticalCenterOffset: parent.radius * 0.4 - text: API.get().empty_string + (General.download_icon + " " + qsTr("New update available!") + " " + qsTr("Version:") + " " + API.get().update_status.new_version + " - " + qsTr("Click here for the details.")) + text: API.get().settings_pg.empty_string + (General.download_icon + " " + qsTr("New update available!") + " " + qsTr("Version:") + " " + API.get().update_status.new_version + " - " + qsTr("Click here for the details.")) font.pixelSize: Style.textSizeSmall3 color: Style.colorWhite10 } diff --git a/atomic_qt_design/qml/Components/WalletNameField.qml b/atomic_qt_design/qml/Components/WalletNameField.qml index d48965c93a..56b60041cb 100644 --- a/atomic_qt_design/qml/Components/WalletNameField.qml +++ b/atomic_qt_design/qml/Components/WalletNameField.qml @@ -6,8 +6,8 @@ import QtQuick.Controls 2.12 import "../Constants" TextFieldWithTitle { id: input_wallet_name - title: API.get().empty_string + (qsTr("Wallet Name")) - field.placeholderText: API.get().empty_string + (qsTr("Enter the name of your wallet here")) + title: API.get().settings_pg.empty_string + (qsTr("Wallet Name")) + field.placeholderText: API.get().settings_pg.empty_string + (qsTr("Enter the name of your wallet here")) field.validator: RegExpValidator { regExp: /[a-zA-Z0-9]+/ } required: true diff --git a/atomic_qt_design/qml/Constants/General.qml b/atomic_qt_design/qml/Constants/General.qml index 732e11b8bb..2020fff5af 100644 --- a/atomic_qt_design/qml/Constants/General.qml +++ b/atomic_qt_design/qml/Constants/General.qml @@ -121,7 +121,7 @@ QtObject { function formatFiat(received, amount, fiat) { return diffPrefix(received) + - (fiat === API.get().current_fiat ? API.get().current_fiat_sign : API.get().current_currency_sign) + (fiat === API.get().settings_pg.current_fiat ? API.get().settings_pg.current_fiat_sign : API.get().settings_pg.current_currency_sign) + " " + nFormatter(parseFloat(amount), 2) } diff --git a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml index 9d219b1162..fa11ef07bd 100644 --- a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml +++ b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml @@ -97,7 +97,7 @@ FloatingBackground { Layout.fillWidth: true Layout.alignment: Qt.AlignLeft | Qt.AlignBottom DefaultText { - text_value: API.get().empty_string + (qsTr("Notifications")) + text_value: API.get().settings_pg.empty_string + (qsTr("Notifications")) font.pixelSize: Style.textSize2 Layout.fillWidth: true Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter @@ -115,7 +115,7 @@ FloatingBackground { DefaultText { id: mark_all_as_read - text_value: API.get().empty_string + (qsTr("Clear") + " ✔️") + text_value: API.get().settings_pg.empty_string + (qsTr("Clear") + " ✔️") font.pixelSize: Style.textSizeSmall3 anchors.centerIn: parent color: Style.colorWhite10 @@ -142,7 +142,7 @@ FloatingBackground { DefaultText { anchors.centerIn: parent visible: !list.visible - text_value: API.get().empty_string + (qsTr("There isn't any notification")) + text_value: API.get().settings_pg.empty_string + (qsTr("There isn't any notification")) font.pixelSize: Style.textSizeSmall2 } @@ -163,7 +163,7 @@ FloatingBackground { anchors.topMargin: 10 anchors.right: parent.right anchors.rightMargin: 25 - text_value: API.get().empty_string + (modelData.time) + text_value: API.get().settings_pg.empty_string + (modelData.time) font.pixelSize: Style.textSizeSmall } @@ -173,13 +173,13 @@ FloatingBackground { anchors.leftMargin: 10 DefaultText { - text_value: API.get().empty_string + (modelData.title) + text_value: API.get().settings_pg.empty_string + (modelData.title) font.pixelSize: Style.textSizeSmall4 font.bold: true } DefaultText { - text_value: API.get().empty_string + (modelData.message) + text_value: API.get().settings_pg.empty_string + (modelData.message) font.pixelSize: Style.textSizeSmall1 } } @@ -209,7 +209,7 @@ FloatingBackground { DefaultText { id: remove_button - text_value: API.get().empty_string + ("✔️") + text_value: API.get().settings_pg.empty_string + ("✔️") anchors.centerIn: parent font.pixelSize: Style.textSizeSmall3 color: Style.colorWhite10 @@ -234,14 +234,14 @@ FloatingBackground { spacing: 10 // DefaultButton { -// text: API.get().empty_string + (qsTr("Pop Test Notification")) +// text: API.get().settings_pg.empty_string + (qsTr("Pop Test Notification")) // onClicked: { // onSwapStatusUpdated("ongoing", "finished", Date.now().toString(), "BTC", "KMD", "13.3.1337") // } // } DefaultButton { - text: API.get().empty_string + (qsTr("Close")) + text: API.get().settings_pg.empty_string + (qsTr("Close")) onClicked: root.visible = false } } diff --git a/atomic_qt_design/qml/Exchange/Exchange.qml b/atomic_qt_design/qml/Exchange/Exchange.qml index fd7bbbbca4..3f4fe8cfa0 100644 --- a/atomic_qt_design/qml/Exchange/Exchange.qml +++ b/atomic_qt_design/qml/Exchange/Exchange.qml @@ -92,7 +92,7 @@ Item { ExchangeTab { dashboard_index: General.idx_exchange_trade - text_value: API.get().empty_string + (qsTr("Trade")) + text_value: API.get().settings_pg.empty_string + (qsTr("Trade")) } VerticalLineBasic { @@ -103,7 +103,7 @@ Item { ExchangeTab { dashboard_index: General.idx_exchange_orders - text_value: API.get().empty_string + (qsTr("Orders")) + text_value: API.get().settings_pg.empty_string + (qsTr("Orders")) } VerticalLineBasic { @@ -113,7 +113,7 @@ Item { ExchangeTab { dashboard_index: General.idx_exchange_history - text_value: API.get().empty_string + (qsTr("History")) + text_value: API.get().settings_pg.empty_string + (qsTr("History")) } } } diff --git a/atomic_qt_design/qml/Exchange/History/History.qml b/atomic_qt_design/qml/Exchange/History/History.qml index 63fd603da4..a71b7f92b9 100644 --- a/atomic_qt_design/qml/Exchange/History/History.qml +++ b/atomic_qt_design/qml/Exchange/History/History.qml @@ -40,7 +40,7 @@ Item { spacing: 15 SwapList { - title: API.get().empty_string + (qsTr("Recent Swaps")) + title: API.get().settings_pg.empty_string + (qsTr("Recent Swaps")) items: API.get().orders_mdl } } @@ -52,7 +52,7 @@ Item { LogModal { id: recover_funds_modal - title: API.get().empty_string + (qsTr("Recover Funds Result")) + title: API.get().settings_pg.empty_string + (qsTr("Recover Funds Result")) field.text: General.prettifyJSON(recover_funds_result) onClosed: recover_funds_result = "{}" diff --git a/atomic_qt_design/qml/Exchange/History/SwapList.qml b/atomic_qt_design/qml/Exchange/History/SwapList.qml index c10808df8a..e5bbfe474f 100644 --- a/atomic_qt_design/qml/Exchange/History/SwapList.qml +++ b/atomic_qt_design/qml/Exchange/History/SwapList.qml @@ -29,7 +29,7 @@ InnerBackground { height: parent.height DefaultText { - text_value: API.get().empty_string + (title + " (" + items.length + ")") + text_value: API.get().settings_pg.empty_string + (title + " (" + items.length + ")") Layout.alignment: Qt.AlignHCenter | Qt.AlignTop Layout.topMargin: 10 @@ -50,7 +50,7 @@ InnerBackground { Layout.topMargin: 20 color: Style.colorWhite5 - text_value: API.get().empty_string + (qsTr("You don't have recent orders.")) + text_value: API.get().settings_pg.empty_string + (qsTr("You don't have recent orders.")) } // List diff --git a/atomic_qt_design/qml/Exchange/OrderContent.qml b/atomic_qt_design/qml/Exchange/OrderContent.qml index 2fe257736d..92249def45 100644 --- a/atomic_qt_design/qml/Exchange/OrderContent.qml +++ b/atomic_qt_design/qml/Exchange/OrderContent.qml @@ -40,7 +40,7 @@ Item { // Base Amount DefaultText { id: base_amount - text_value: API.get().empty_string + (!details ? "" : + text_value: API.get().settings_pg.empty_string + (!details ? "" : "~ " + General.formatCrypto("", details.base_amount, details.base_coin)) font.pixelSize: in_modal ? Style.textSize2 : Style.textSize @@ -62,7 +62,7 @@ Item { // Rel Amount DefaultText { id: rel_amount - text_value: API.get().empty_string + (!details ? "" : + text_value: API.get().settings_pg.empty_string + (!details ? "" : "~ " + General.formatCrypto("", details.rel_amount, details.rel_coin)) font.pixelSize: base_amount.font.pixelSize @@ -75,7 +75,7 @@ Item { DefaultText { id: order_id visible: !in_modal && is_placed_order - text_value: API.get().empty_string + (!details ? "" : + text_value: API.get().settings_pg.empty_string + (!details ? "" : qsTr("ID") + ": " + details.order_id) color: Style.colorTheme2 anchors.top: base_amount.bottom @@ -89,7 +89,7 @@ Item { color: !details ? "white" : visible ? getStatusColor(details.order_status) : '' anchors.horizontalCenter: parent.horizontalCenter anchors.top: base_icon.top - text_value: API.get().empty_string + (!details ? "" : + text_value: API.get().settings_pg.empty_string + (!details ? "" : visible ? getStatusTextWithPrefix(details.order_status) : '') } @@ -97,7 +97,7 @@ Item { DefaultText { id: date visible: !details ? false : !in_modal && details.date !== '' - text_value: API.get().empty_string + (!details ? "" : + text_value: API.get().settings_pg.empty_string + (!details ? "" : details.date) color: Style.colorTheme2 anchors.top: order_id.bottom @@ -107,7 +107,7 @@ Item { // Maker/Taker DefaultText { visible: !in_modal && is_placed_order - text_value: API.get().empty_string + (!details ? "" : + text_value: API.get().settings_pg.empty_string + (!details ? "" : details.is_maker ? qsTr("Maker Order"): qsTr("Taker Order")) color: Style.colorThemeDarkLight anchors.verticalCenter: date.verticalCenter @@ -120,7 +120,7 @@ Item { !in_modal && details.cancellable anchors.right: parent.right anchors.bottom: date.bottom - text: API.get().empty_string + (qsTr("Cancel")) + text: API.get().settings_pg.empty_string + (qsTr("Cancel")) onClicked: onCancelOrder(details.order_id) } @@ -130,7 +130,7 @@ Item { !in_modal && details.recoverable anchors.right: parent.right anchors.bottom: date.bottom - text: API.get().empty_string + (qsTr("Recover Funds")) + text: API.get().settings_pg.empty_string + (qsTr("Recover Funds")) onClicked: { if(details) onRecoverFunds(details.order_id) } } } diff --git a/atomic_qt_design/qml/Exchange/OrderModal.qml b/atomic_qt_design/qml/Exchange/OrderModal.qml index 92a5815bf0..5647b1af72 100644 --- a/atomic_qt_design/qml/Exchange/OrderModal.qml +++ b/atomic_qt_design/qml/Exchange/OrderModal.qml @@ -22,7 +22,7 @@ DefaultModal { anchors.horizontalCenter: parent.horizontalCenter ModalHeader { - title: API.get().empty_string + (!details ? "" : + title: API.get().settings_pg.empty_string + (!details ? "" : details.is_swap ? qsTr("Swap Details") : qsTr("Order Details")) } @@ -52,7 +52,7 @@ DefaultModal { details.is_swap || !details.is_maker color: !details ? "white" : visible ? getStatusColor(details.order_status) : '' - text_value: API.get().empty_string + (!details ? "" : + text_value: API.get().settings_pg.empty_string + (!details ? "" : visible ? getStatusTextWithPrefix(details.order_status) : '') } @@ -75,7 +75,7 @@ DefaultModal { // Maker/Taker DefaultText { - text_value: API.get().empty_string + (!details ? "" : + text_value: API.get().settings_pg.empty_string + (!details ? "" : details.is_maker ? qsTr("Maker Order"): qsTr("Taker Order")) color: Style.colorThemeDarkLight Layout.alignment: Qt.AlignRight @@ -85,7 +85,7 @@ DefaultModal { TextFieldWithTitle { Layout.topMargin: -20 - title: API.get().empty_string + (qsTr("Refund State")) + title: API.get().settings_pg.empty_string + (qsTr("Refund State")) field.text: !details ? "" : details.order_status === "refunding" ? qsTr("Your swap failed but the auto-refund process for your payment started already. Please wait and keep application opened until you receive your payment back") : "" field.readOnly: true @@ -95,16 +95,16 @@ DefaultModal { // Date TextWithTitle { - title: API.get().empty_string + (qsTr("Date")) - text: API.get().empty_string + (!details ? "" : + title: API.get().settings_pg.empty_string + (qsTr("Date")) + text: API.get().settings_pg.empty_string + (!details ? "" : details.date) visible: text !== '' } // ID TextWithTitle { - title: API.get().empty_string + (qsTr("ID")) - text: API.get().empty_string + (!details ? "" : + title: API.get().settings_pg.empty_string + (qsTr("ID")) + text: API.get().settings_pg.empty_string + (!details ? "" : details.order_id) visible: text !== '' privacy: true @@ -112,9 +112,9 @@ DefaultModal { // Payment ID TextWithTitle { - title: API.get().empty_string + (!details ? "" : + title: API.get().settings_pg.empty_string + (!details ? "" : details.is_maker ? qsTr("Maker Payment Sent ID") : qsTr("Maker Payment Spent ID")) - text: API.get().empty_string + (!details ? "" : + text: API.get().settings_pg.empty_string + (!details ? "" : details.maker_payment_id) visible: text !== '' privacy: true @@ -122,9 +122,9 @@ DefaultModal { // Payment ID TextWithTitle { - title: API.get().empty_string + (!details ? "" : + title: API.get().settings_pg.empty_string + (!details ? "" : details.is_maker ? qsTr("Taker Payment Spent ID") : qsTr("Taker Payment Sent ID")) - text: API.get().empty_string + (!details ? "" : + text: API.get().settings_pg.empty_string + (!details ? "" : details.taker_payment_id) visible: text !== '' privacy: true @@ -132,16 +132,16 @@ DefaultModal { // Error ID TextWithTitle { - title: API.get().empty_string + (qsTr("Error ID")) - text: API.get().empty_string + (!details ? "" : + title: API.get().settings_pg.empty_string + (qsTr("Error ID")) + text: API.get().settings_pg.empty_string + (!details ? "" : details.order_error_state) visible: text !== '' } // Error Details TextFieldWithTitle { - title: API.get().empty_string + (qsTr("Error Log")) - field.text: API.get().empty_string + (!details ? "" : + title: API.get().settings_pg.empty_string + (qsTr("Error Log")) + field.text: API.get().settings_pg.empty_string + (!details ? "" : details.order_error_message) field.readOnly: true copyable: true @@ -152,7 +152,7 @@ DefaultModal { // Buttons RowLayout { DefaultButton { - text: API.get().empty_string + (qsTr("Close")) + text: API.get().settings_pg.empty_string + (qsTr("Close")) Layout.fillWidth: true onClicked: root.close() } @@ -162,12 +162,12 @@ DefaultModal { visible: !details ? false : details.cancellable Layout.fillWidth: true - text: API.get().empty_string + (qsTr("Cancel Order")) + text: API.get().settings_pg.empty_string + (qsTr("Cancel Order")) onClicked: { if(details) onCancelOrder(details.order_id) } } PrimaryButton { - text: API.get().empty_string + (qsTr("View at Explorer")) + text: API.get().settings_pg.empty_string + (qsTr("View at Explorer")) Layout.fillWidth: true visible: !details ? false : details.maker_payment_id !== '' || details.taker_payment_id !== '' diff --git a/atomic_qt_design/qml/Exchange/Orders/OrderList.qml b/atomic_qt_design/qml/Exchange/Orders/OrderList.qml index 80ccb988a8..f4c3914801 100644 --- a/atomic_qt_design/qml/Exchange/Orders/OrderList.qml +++ b/atomic_qt_design/qml/Exchange/Orders/OrderList.qml @@ -18,7 +18,7 @@ InnerBackground { height: parent.height DefaultText { - text_value: API.get().empty_string + (title + " (" + items.length + ")") + text_value: API.get().settings_pg.empty_string + (title + " (" + items.length + ")") Layout.alignment: Qt.AlignHCenter | Qt.AlignTop Layout.topMargin: 10 @@ -39,7 +39,7 @@ InnerBackground { Layout.topMargin: 20 color: Style.colorWhite5 - text_value: API.get().empty_string + (qsTr("You don't have any orders.")) + text_value: API.get().settings_pg.empty_string + (qsTr("You don't have any orders.")) } // List diff --git a/atomic_qt_design/qml/Exchange/Orders/Orders.qml b/atomic_qt_design/qml/Exchange/Orders/Orders.qml index fafae40a58..06b4c24421 100644 --- a/atomic_qt_design/qml/Exchange/Orders/Orders.qml +++ b/atomic_qt_design/qml/Exchange/Orders/Orders.qml @@ -87,7 +87,7 @@ Item { Switch { id: show_all_coins Layout.leftMargin: 15 - text: API.get().empty_string + (qsTr("Show All Coins")) + text: API.get().settings_pg.empty_string + (qsTr("Show All Coins")) checked: true onCheckedChanged: applyFilter() @@ -118,7 +118,7 @@ Item { } DangerButton { - text: API.get().empty_string + (show_all_coins.checked ? qsTr("Cancel All Orders") : qsTr("Cancel All %1 Orders", "TICKER").arg(base)) + text: API.get().settings_pg.empty_string + (show_all_coins.checked ? qsTr("Cancel All Orders") : qsTr("Cancel All %1 Orders", "TICKER").arg(base)) enabled: orders_model.length > 0 onClicked: { if(show_all_coins.checked) API.get().trading_pg.cancel_all_orders() @@ -137,7 +137,7 @@ Item { spacing: parent.spacing OrderList { - title: API.get().empty_string + (show_all_coins.checked ? qsTr("All Orders") : qsTr("All %1 Orders", "TICKER").arg(base)) + title: API.get().settings_pg.empty_string + (show_all_coins.checked ? qsTr("All Orders") : qsTr("All %1 Orders", "TICKER").arg(base)) items: orders_model } } diff --git a/atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml b/atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml index b8951d6b99..3420497c5c 100644 --- a/atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml +++ b/atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml @@ -636,7 +636,7 @@ Item { DefaultText { visible: !pair_supported - text_value: API.get().empty_string + (qsTr("There is no chart data for this pair yet")) + text_value: API.get().settings_pg.empty_string + (qsTr("There is no chart data for this pair yet")) anchors.centerIn: parent } } diff --git a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml index a52eb604ba..b4df1d3842 100644 --- a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml +++ b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml @@ -24,7 +24,7 @@ DefaultModal { width: parent.width ModalHeader { - title: API.get().empty_string + (qsTr("Confirm Exchange Details")) + title: API.get().settings_pg.empty_string + (qsTr("Confirm Exchange Details")) } OrderContent { @@ -73,13 +73,13 @@ DefaultModal { DefaultText { Layout.alignment: Qt.AlignHCenter - text_value: API.get().empty_string + (qsTr("This swap request can not be undone and is a final event!")) + text_value: API.get().settings_pg.empty_string + (qsTr("This swap request can not be undone and is a final event!")) } DefaultText { Layout.alignment: Qt.AlignHCenter - text_value: API.get().empty_string + (qsTr("This transaction can take up to 10 mins - DO NOT close this application!")) + text_value: API.get().settings_pg.empty_string + (qsTr("This transaction can take up to 10 mins - DO NOT close this application!")) font.pixelSize: Style.textSizeSmall4 } } @@ -104,13 +104,13 @@ DefaultModal { DefaultText { Layout.alignment: Qt.AlignHCenter - text_value: API.get().empty_string + (qsTr("Security configuration")) + text_value: API.get().settings_pg.empty_string + (qsTr("Security configuration")) font.bold: true } DefaultText { Layout.alignment: Qt.AlignHCenter - text_value: API.get().empty_string + ("✅ " + + text_value: API.get().settings_pg.empty_string + ("✅ " + (config_section.is_dpow_configurable ? qsTr("dPoW protected") : qsTr("%1 confirmations for incoming transactions").arg(config_section.default_config.required_confirmations))) } @@ -122,7 +122,7 @@ DefaultModal { Layout.alignment: Qt.AlignHCenter id: enable_custom_config - text: API.get().empty_string + (qsTr("Use custom protection settings for incoming %1 transactions", "TICKER").arg(rel_ticker)) + text: API.get().settings_pg.empty_string + (qsTr("Use custom protection settings for incoming %1 transactions", "TICKER").arg(rel_ticker)) } // Configuration settings @@ -143,13 +143,13 @@ DefaultModal { if(checked) enable_normal_confs.checked = true } - text: API.get().empty_string + (qsTr("Enable Komodo dPoW security")) + text: API.get().settings_pg.empty_string + (qsTr("Enable Komodo dPoW security")) } DefaultText { visible: enable_dpow_confs.visible && enable_dpow_confs.enabled Layout.alignment: Qt.AlignHCenter - text_value: API.get().empty_string + (General.cex_icon + " " + qsTr('Read more about dPoW')) + text_value: API.get().settings_pg.empty_string + (General.cex_icon + " " + qsTr('Read more about dPoW')) wrapMode: Text.WordWrap font.pixelSize: Style.textSizeSmall2 @@ -166,7 +166,7 @@ DefaultModal { enabled: !config_section.is_dpow_configurable || !enable_dpow_confs.checked checked: true - text: API.get().empty_string + (qsTr("Change required confirmations")) + text: API.get().settings_pg.empty_string + (qsTr("Change required confirmations")) } // Normal configuration settings @@ -177,7 +177,7 @@ DefaultModal { DefaultText { Layout.alignment: Qt.AlignHCenter - text_value: API.get().empty_string + (qsTr("Confirmations") + ": " + required_confirmation_count.value) + text_value: API.get().settings_pg.empty_string + (qsTr("Confirmations") + ": " + required_confirmation_count.value) color: parent.enabled ? Style.colorText : Style.colorTextDisabled } @@ -213,7 +213,7 @@ DefaultModal { DefaultText { Layout.alignment: Qt.AlignHCenter - text_value: API.get().empty_string + ("⚠️ " + qsTr("Warning, this atomic swap is not dPoW protected!")) + text_value: API.get().settings_pg.empty_string + ("⚠️ " + qsTr("Warning, this atomic swap is not dPoW protected!")) } } } @@ -222,13 +222,13 @@ DefaultModal { // Buttons RowLayout { DefaultButton { - text: API.get().empty_string + (qsTr("Cancel")) + text: API.get().settings_pg.empty_string + (qsTr("Cancel")) Layout.fillWidth: true onClicked: root.close() } PrimaryButton { - text: API.get().empty_string + (qsTr("Confirm")) + text: API.get().settings_pg.empty_string + (qsTr("Confirm")) Layout.fillWidth: true onClicked: { trade(left_ticker, right_ticker, { diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index fe342c8eef..76983cb07f 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -17,7 +17,7 @@ FloatingBackground { property string total_amount: "0" function getFiatText(v, ticker) { - return General.formatFiat('', v === '' ? 0 : API.get().get_fiat_from_amount(ticker, v), API.get().current_fiat) + " " + General.cex_icon + return General.formatFiat('', v === '' ? 0 : API.get().get_fiat_from_amount(ticker, v), API.get().settings_pg.current_fiat) + " " + General.cex_icon } function getVolume() { @@ -182,7 +182,7 @@ FloatingBackground { DefaultButton { font.pixelSize: Style.textSize - text: API.get().empty_string + (qsTr("Sell")) + text: API.get().settings_pg.empty_string + (qsTr("Sell")) color: sell_mode ? Style.colorRed : Style.colorRed3 colorTextEnabled: sell_mode ? Style.colorWhite1 : Style.colorWhite6 font.weight: Font.Bold @@ -190,7 +190,7 @@ FloatingBackground { } DefaultButton { font.pixelSize: Style.textSize - text: API.get().empty_string + (qsTr("Buy")) + text: API.get().settings_pg.empty_string + (qsTr("Buy")) color: sell_mode ? Style.colorGreen3 : Style.colorGreen colorTextEnabled: sell_mode ? Style.colorWhite8 : Style.colorWhite1 font.weight: Font.Bold @@ -211,7 +211,7 @@ FloatingBackground { Layout.fillWidth: true enabled: input_volume.field.enabled - field.left_text: API.get().empty_string + (qsTr("Price")) + field.left_text: API.get().settings_pg.empty_string + (qsTr("Price")) field.right_text: right_ticker field.onTextChanged: { @@ -240,9 +240,9 @@ FloatingBackground { width: parent.width field.enabled: root.enabled && !shouldBlockInput() - field.left_text: API.get().empty_string + (qsTr("Volume")) + field.left_text: API.get().settings_pg.empty_string + (qsTr("Volume")) field.right_text: left_ticker - field.placeholderText: API.get().empty_string + (is_sell_form ? qsTr("Amount to sell") : qsTr("Amount to receive")) + field.placeholderText: API.get().settings_pg.empty_string + (is_sell_form ? qsTr("Amount to sell") : qsTr("Amount to receive")) field.onTextChanged: { const before_checks = field.text onInputChanged() @@ -312,21 +312,21 @@ FloatingBackground { anchors.left: parent.left anchors.top: parent.bottom - text_value: API.get().empty_string + (qsTr("Min")) + text_value: API.get().settings_pg.empty_string + (qsTr("Min")) font.pixelSize: input_volume.field.font.pixelSize } DefaultText { anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.bottom - text_value: API.get().empty_string + (qsTr("Half")) + text_value: API.get().settings_pg.empty_string + (qsTr("Half")) font.pixelSize: input_volume.field.font.pixelSize } DefaultText { anchors.right: parent.right anchors.top: parent.bottom - text_value: API.get().empty_string + (qsTr("Max")) + text_value: API.get().settings_pg.empty_string + (qsTr("Max")) font.pixelSize: input_volume.field.font.pixelSize } } @@ -355,7 +355,7 @@ FloatingBackground { DefaultText { id: tx_fee_text - text_value: API.get().empty_string + ((qsTr('Transaction Fee') + ': ' + General.formatCrypto("", curr_trade_info.tx_fee, curr_trade_info.is_ticker_of_fees_eth ? "ETH" : base_ticker)) + + text_value: API.get().settings_pg.empty_string + ((qsTr('Transaction Fee') + ': ' + General.formatCrypto("", curr_trade_info.tx_fee, curr_trade_info.is_ticker_of_fees_eth ? "ETH" : base_ticker)) + // ETH Fees (hasEthFees() ? " + " + General.formatCrypto("", curr_trade_info.erc_fees, 'ETH') : '') + @@ -373,7 +373,7 @@ FloatingBackground { } DefaultText { - text_value: API.get().empty_string + (qsTr('Trading Fee') + ': ' + General.formatCrypto("", curr_trade_info.trade_fee, base_ticker) + + text_value: API.get().settings_pg.empty_string + (qsTr('Trading Fee') + ': ' + General.formatCrypto("", curr_trade_info.trade_fee, base_ticker) + // Fiat part (" ("+ @@ -390,7 +390,7 @@ FloatingBackground { DefaultText { visible: !fees.visible - text_value: API.get().empty_string + (qsTr('Fees will be calculated')) + text_value: API.get().settings_pg.empty_string + (qsTr('Fees will be calculated')) Layout.alignment: Qt.AlignCenter font.pixelSize: tx_fee_text.font.pixelSize } @@ -408,7 +408,7 @@ FloatingBackground { DefaultText { Layout.alignment: Qt.AlignLeft - text_value: API.get().empty_string + (qsTr("Total") + ": " + General.formatCrypto("", total_amount, right_ticker)) + text_value: API.get().settings_pg.empty_string + (qsTr("Total") + ": " + General.formatCrypto("", total_amount, right_ticker)) font.pixelSize: Style.textSizeSmall3 } @@ -422,7 +422,7 @@ FloatingBackground { width: 170 - text: API.get().empty_string + (is_sell_form ? qsTr("Sell %1", "TICKER").arg(left_ticker) : qsTr("Buy %1", "TICKER").arg(left_ticker)) + text: API.get().settings_pg.empty_string + (is_sell_form ? qsTr("Sell %1", "TICKER").arg(left_ticker) : qsTr("Buy %1", "TICKER").arg(left_ticker)) enabled: valid_trade_info && !notEnoughBalanceForFees() && isValid() onClicked: confirm_trade_modal.open() } diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml index 8948dcc8b7..0e80f1f40f 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml @@ -24,7 +24,7 @@ ColumnLayout { id: price_header font.pixelSize: Style.textSizeSmall2 - text_value: API.get().empty_string + (is_asks ? qsTr("Ask Price") + "\n(" + right_ticker + ")": + text_value: API.get().settings_pg.empty_string + (is_asks ? qsTr("Ask Price") + "\n(" + right_ticker + ")": qsTr("Bid Price") + "\n(" + right_ticker + ")") color: is_asks ? Style.colorRed : Style.colorGreen @@ -50,7 +50,7 @@ ColumnLayout { font.pixelSize: price_header.font.pixelSize - text_value: API.get().empty_string + (qsTr("Quantity") + "\n(" + left_ticker + ")") + text_value: API.get().settings_pg.empty_string + (qsTr("Quantity") + "\n(" + left_ticker + ")") color: Style.colorWhite1 anchors.verticalCenter: parent.verticalCenter } @@ -67,7 +67,7 @@ ColumnLayout { font.pixelSize: price_header.font.pixelSize - text_value: API.get().empty_string + (qsTr("Total") + "\n(" + right_ticker + ")") + text_value: API.get().settings_pg.empty_string + (qsTr("Total") + "\n(" + right_ticker + ")") color: Style.colorWhite1 anchors.verticalCenter: parent.verticalCenter } @@ -138,7 +138,7 @@ ColumnLayout { font.pixelSize: Style.textSizeSmall1 - text_value: API.get().empty_string + (General.formatDouble(price)) + text_value: API.get().settings_pg.empty_string + (General.formatDouble(price)) color: price_header.color anchors.verticalCenter: parent.verticalCenter } @@ -153,7 +153,7 @@ ColumnLayout { font.pixelSize: price_value.font.pixelSize - text_value: API.get().empty_string + (quantity) + text_value: API.get().settings_pg.empty_string + (quantity) color: Style.colorWhite4 anchors.verticalCenter: parent.verticalCenter } @@ -168,7 +168,7 @@ ColumnLayout { font.pixelSize: price_value.font.pixelSize - text_value: API.get().empty_string + (total) + text_value: API.get().settings_pg.empty_string + (total) color: Style.colorWhite4 anchors.verticalCenter: parent.verticalCenter } diff --git a/atomic_qt_design/qml/Exchange/Trade/PriceLine.qml b/atomic_qt_design/qml/Exchange/Trade/PriceLine.qml index 4b0a3221d4..e9d6231710 100644 --- a/atomic_qt_design/qml/Exchange/Trade/PriceLine.qml +++ b/atomic_qt_design/qml/Exchange/Trade/PriceLine.qml @@ -29,7 +29,7 @@ RowLayout { DefaultText { visible: !price_entered && invalid_cex_price Layout.alignment: Qt.AlignHCenter - text_value: API.get().empty_string + (qsTr("Fill the amounts to see the price information")) + text_value: API.get().settings_pg.empty_string + (qsTr("Fill the amounts to see the price information")) font.pixelSize: fontSize } @@ -40,14 +40,14 @@ RowLayout { DefaultText { Layout.alignment: Qt.AlignHCenter - text_value: API.get().empty_string + (qsTr("Exchange rate") + (orderIsSelected() ? (" (" + qsTr("Selected") + ")") : "")) + text_value: API.get().settings_pg.empty_string + (qsTr("Exchange rate") + (orderIsSelected() ? (" (" + qsTr("Selected") + ")") : "")) font.pixelSize: fontSize } // Price reversed DefaultText { Layout.alignment: Qt.AlignHCenter - text_value: API.get().empty_string + ("1 " + right_ticker + " = " + General.formatCrypto("", General.formatDouble(1 / parseFloat(price)), left_ticker)) + text_value: API.get().settings_pg.empty_string + ("1 " + right_ticker + " = " + General.formatCrypto("", General.formatDouble(1 / parseFloat(price)), left_ticker)) font.pixelSize: fontSizeBigger font.bold: true } @@ -55,7 +55,7 @@ RowLayout { // Price DefaultText { Layout.alignment: Qt.AlignHCenter - text_value: API.get().empty_string + ("1 " + left_ticker + " = " + General.formatCrypto("", price, right_ticker)) + text_value: API.get().settings_pg.empty_string + ("1 " + left_ticker + " = " + General.formatCrypto("", price, right_ticker)) font.pixelSize: fontSize } } @@ -72,14 +72,14 @@ RowLayout { Layout.bottomMargin: Layout.topMargin Layout.alignment: Qt.AlignHCenter color: price_diff <= 0 ? Style.colorGreen : Style.colorRed - text_value: API.get().empty_string + ((price_diff > 0 ? qsTr("Expensive") : qsTr("Expedient")) + ":    " + qsTr("%1 compared to CEX", "PRICE_DIFF%").arg("" + General.formatPercent(limitDigits(price_diff)) + "")) + text_value: API.get().settings_pg.empty_string + ((price_diff > 0 ? qsTr("Expensive") : qsTr("Expedient")) + ":    " + qsTr("%1 compared to CEX", "PRICE_DIFF%").arg("" + General.formatPercent(limitDigits(price_diff)) + "")) font.pixelSize: fontSize } RowLayout { Layout.alignment: Qt.AlignHCenter DefaultText { - text_value: API.get().empty_string + (General.formatPercent(line_scale)) + text_value: API.get().settings_pg.empty_string + (General.formatPercent(line_scale)) font.pixelSize: fontSize } @@ -100,7 +100,7 @@ RowLayout { } DefaultText { - text_value: API.get().empty_string + (General.formatPercent(-line_scale)) + text_value: API.get().settings_pg.empty_string + (General.formatPercent(-line_scale)) font.pixelSize: fontSize } } @@ -117,7 +117,7 @@ RowLayout { DefaultText { Layout.alignment: Qt.AlignHCenter - text_value: API.get().empty_string + (General.cex_icon + " " + qsTr("CEXchange rate")) + text_value: API.get().settings_pg.empty_string + (General.cex_icon + " " + qsTr("CEXchange rate")) font.pixelSize: fontSize CexInfoTrigger {} @@ -126,7 +126,7 @@ RowLayout { // Price reversed DefaultText { Layout.alignment: Qt.AlignHCenter - text_value: API.get().empty_string + ("1 " + right_ticker + " = " + General.formatCrypto("", General.formatDouble(1 / parseFloat(cex_price)), left_ticker)) + text_value: API.get().settings_pg.empty_string + ("1 " + right_ticker + " = " + General.formatCrypto("", General.formatDouble(1 / parseFloat(cex_price)), left_ticker)) font.pixelSize: fontSizeBigger font.bold: true } @@ -134,7 +134,7 @@ RowLayout { // Price DefaultText { Layout.alignment: Qt.AlignHCenter - text_value: API.get().empty_string + ("1 " + left_ticker + " = " + General.formatCrypto("", cex_price, right_ticker)) + text_value: API.get().settings_pg.empty_string + ("1 " + left_ticker + " = " + General.formatCrypto("", cex_price, right_ticker)) font.pixelSize: fontSize } } diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index 1f1cecefcb..e81016583c 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -419,7 +419,7 @@ Item { font.pixelSize: Style.textSizeSmall4 color: Style.colorRed - text_value: API.get().empty_string + ( + text_value: API.get().settings_pg.empty_string + ( General.isZero(getCurrentPrice()) ? (qsTr("Please fill the price field")) : notEnoughBalance() ? (qsTr("%1 balance is lower than minimum trade amount").arg(base_ticker) + " : " + General.getMinTradeAmount()) : notEnoughBalanceForFees() ? diff --git a/atomic_qt_design/qml/NoConnection.qml b/atomic_qt_design/qml/NoConnection.qml index d418e1b800..a4cb6c9127 100644 --- a/atomic_qt_design/qml/NoConnection.qml +++ b/atomic_qt_design/qml/NoConnection.qml @@ -17,19 +17,19 @@ Rectangle { anchors.verticalCenter: parent.verticalCenter DefaultText { - text_value: API.get().empty_string + (qsTr("No connection")) + text_value: API.get().settings_pg.empty_string + (qsTr("No connection")) Layout.alignment: Qt.AlignHCenter font.pixelSize: Style.textSize3 } DefaultText { - text_value: API.get().empty_string + (qsTr("Please make sure you are connected to the internet")) + text_value: API.get().settings_pg.empty_string + (qsTr("Please make sure you are connected to the internet")) Layout.alignment: Qt.AlignHCenter } DefaultText { - text_value: API.get().empty_string + (qsTr("Will automatically retry in %1 seconds").arg(General.formatDouble(API.get().internet_checker.seconds_left_to_auto_retry, 0))) + text_value: API.get().settings_pg.empty_string + (qsTr("Will automatically retry in %1 seconds").arg(General.formatDouble(API.get().internet_checker.seconds_left_to_auto_retry, 0))) Layout.alignment: Qt.AlignHCenter } @@ -38,7 +38,7 @@ Rectangle { } DefaultButton { - text: API.get().empty_string + (qsTr("Retry")) + text: API.get().settings_pg.empty_string + (qsTr("Retry")) onClicked: API.get().internet_checker.retry() Layout.alignment: Qt.AlignHCenter } diff --git a/atomic_qt_design/qml/Portfolio/Portfolio.qml b/atomic_qt_design/qml/Portfolio/Portfolio.qml index cf0a668922..8f84075bbe 100644 --- a/atomic_qt_design/qml/Portfolio/Portfolio.qml +++ b/atomic_qt_design/qml/Portfolio/Portfolio.qml @@ -70,7 +70,7 @@ ColumnLayout { Layout.topMargin: 50 Layout.bottomMargin: 0 Layout.alignment: Qt.AlignHCenter - text_value: API.get().empty_string + (qsTr("TOTAL")) + text_value: API.get().settings_pg.empty_string + (qsTr("TOTAL")) font.pixelSize: Style.textSize color: Style.colorWhite5 } @@ -79,7 +79,7 @@ ColumnLayout { DefaultText { Layout.alignment: Qt.AlignHCenter Layout.bottomMargin: 30 - text_value: API.get().empty_string + (General.formatFiat("", API.get().balance_fiat_all, API.get().current_currency)) + text_value: API.get().settings_pg.empty_string + (General.formatFiat("", API.get().balance_fiat_all, API.get().settings_pg.current_currency)) font.pixelSize: Style.textSize4 privacy: true } @@ -89,12 +89,12 @@ ColumnLayout { anchors.fill: top_layout onClicked: { - const current_fiat = API.get().current_currency - const available_fiats = API.get().get_available_currencies() + const current_fiat = API.get().settings_pg.current_currency + const available_fiats = API.get().settings_pg.get_available_currencies() const current_index = available_fiats.indexOf(current_fiat) const next_index = (current_index + 1) % available_fiats.length const next_fiat = available_fiats[next_index] - API.get().current_currency = next_fiat + API.get().settings_pg.current_currency = next_fiat } } @@ -121,7 +121,7 @@ ColumnLayout { anchors.bottom: parent.bottom anchors.bottomMargin: 10 - placeholderText: API.get().empty_string + (qsTr("Search")) + placeholderText: API.get().settings_pg.empty_string + (qsTr("Search")) selectByMouse: true onTextChanged: { @@ -156,7 +156,7 @@ ColumnLayout { anchors.leftMargin: 40 anchors.verticalCenter: parent.verticalCenter - text: API.get().empty_string + (qsTr("Coin")) + text: API.get().settings_pg.empty_string + (qsTr("Coin")) sort_type: sort_by_name } @@ -168,7 +168,7 @@ ColumnLayout { anchors.leftMargin: parent.width * 0.265 anchors.verticalCenter: parent.verticalCenter - text: API.get().empty_string + (qsTr("Balance")) + text: API.get().settings_pg.empty_string + (qsTr("Balance")) sort_type: sort_by_value } @@ -180,7 +180,7 @@ ColumnLayout { anchors.rightMargin: parent.width * 0.37 anchors.verticalCenter: parent.verticalCenter - text: API.get().empty_string + (qsTr("Change 24h")) + text: API.get().settings_pg.empty_string + (qsTr("Change 24h")) sort_type: sort_by_change } @@ -192,7 +192,7 @@ ColumnLayout { anchors.rightMargin: parent.width * 0.24 anchors.verticalCenter: parent.verticalCenter - text: API.get().empty_string + (qsTr("Trend 7d")) + text: API.get().settings_pg.empty_string + (qsTr("Trend 7d")) sort_type: sort_by_trend } @@ -204,7 +204,7 @@ ColumnLayout { anchors.rightMargin: coin_header.anchors.leftMargin anchors.verticalCenter: parent.verticalCenter - text: API.get().empty_string + (qsTr("Price")) + text: API.get().settings_pg.empty_string + (qsTr("Price")) sort_type: sort_by_price } @@ -229,7 +229,7 @@ ColumnLayout { anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter DefaultText { - text_value: API.get().empty_string + (qsTr("Loading")) + text_value: API.get().settings_pg.empty_string + (qsTr("Loading")) Layout.alignment: Qt.AlignHCenter font.pixelSize: Style.textSize2 } @@ -277,7 +277,7 @@ ColumnLayout { Menu { id: context_menu Action { - text: API.get().empty_string + (qsTr("Disable %1", "TICKER").arg(ticker)) + text: API.get().settings_pg.empty_string + (qsTr("Disable %1", "TICKER").arg(ticker)) onTriggered: API.get().disable_coins([ticker]) enabled: General.canDisable(ticker) } @@ -299,7 +299,7 @@ ColumnLayout { DefaultText { anchors.left: icon.right anchors.leftMargin: 10 - text_value: API.get().empty_string + (name) + text_value: API.get().settings_pg.empty_string + (name) anchors.verticalCenter: parent.verticalCenter } @@ -309,7 +309,7 @@ ColumnLayout { anchors.left: parent.left anchors.leftMargin: balance_header.anchors.leftMargin - text_value: API.get().empty_string + (General.formatCrypto("", balance, ticker, main_currency_balance, API.get().current_currency)) + text_value: API.get().settings_pg.empty_string + (General.formatCrypto("", balance, ticker, main_currency_balance, API.get().settings_pg.current_currency)) color: Style.colorWhite4 anchors.verticalCenter: parent.verticalCenter privacy: true @@ -322,7 +322,7 @@ ColumnLayout { text_value: { const v = parseFloat(change_24h) - return API.get().empty_string + (v === 0 ? '-' : General.formatPercent(v)) + return API.get().settings_pg.empty_string + (v === 0 ? '-' : General.formatPercent(v)) } color: Style.getValueColor(change_24h) anchors.verticalCenter: parent.verticalCenter @@ -333,7 +333,7 @@ ColumnLayout { anchors.right: parent.right anchors.rightMargin: price_header.anchors.rightMargin - text_value: API.get().empty_string + (General.formatFiat('', main_currency_price_for_one_unit, API.get().current_currency)) + text_value: API.get().settings_pg.empty_string + (General.formatFiat('', main_currency_price_for_one_unit, API.get().settings_pg.current_currency)) color: Style.colorThemeDarkLight anchors.verticalCenter: parent.verticalCenter } diff --git a/atomic_qt_design/qml/Screens/Dashboard.qml b/atomic_qt_design/qml/Screens/Dashboard.qml index 4acf428ef9..42d9d03d10 100644 --- a/atomic_qt_design/qml/Screens/Dashboard.qml +++ b/atomic_qt_design/qml/Screens/Dashboard.qml @@ -114,13 +114,13 @@ Item { DefaultText { id: news - text_value: API.get().empty_string + (qsTr("News")) + text_value: API.get().settings_pg.empty_string + (qsTr("News")) function reset() { } } DefaultText { id: dapps - text_value: API.get().empty_string + (qsTr("Dapps")) + text_value: API.get().settings_pg.empty_string + (qsTr("Dapps")) function reset() { } } @@ -217,11 +217,11 @@ Item { width: parent.width ModalHeader { - title: API.get().empty_string + (General.cex_icon + " " + qsTr("CEX Data")) + title: API.get().settings_pg.empty_string + (General.cex_icon + " " + qsTr("CEX Data")) } DefaultText { - text_value: API.get().empty_string + (qsTr('Markets data (prices, charts, etc.) marked with the ⓘ icon originates from third party sources. (coinpaprika.com)')) + text_value: API.get().settings_pg.empty_string + (qsTr('Markets data (prices, charts, etc.) marked with the ⓘ icon originates from third party sources. (coinpaprika.com)')) wrapMode: Text.WordWrap Layout.preferredWidth: cex_rates_modal.width diff --git a/atomic_qt_design/qml/Screens/FirstLaunch.qml b/atomic_qt_design/qml/Screens/FirstLaunch.qml index ed23af25a3..e07888fa9c 100644 --- a/atomic_qt_design/qml/Screens/FirstLaunch.qml +++ b/atomic_qt_design/qml/Screens/FirstLaunch.qml @@ -26,7 +26,7 @@ SetupPage { width: 400 spacing: Style.rowSpacing DefaultText { - text_value: API.get().empty_string + (qsTr("Welcome")) + text_value: API.get().settings_pg.empty_string + (qsTr("Welcome")) } HorizontalLine { @@ -39,13 +39,13 @@ SetupPage { DefaultButton { Layout.fillWidth: true - text: API.get().empty_string + (qsTr("Recover Seed")) + text: API.get().settings_pg.empty_string + (qsTr("Recover Seed")) onClicked: onClickedRecoverSeed() } DefaultButton { Layout.fillWidth: true - text: API.get().empty_string + (qsTr("New User")) + text: API.get().settings_pg.empty_string + (qsTr("New User")) onClicked: onClickedNewUser() } } @@ -58,7 +58,7 @@ SetupPage { // Name DefaultText { - text_value: API.get().empty_string + (qsTr("Wallets")) + text_value: API.get().settings_pg.empty_string + (qsTr("Wallets")) font.pixelSize: Style.textSizeSmall2 } @@ -98,7 +98,7 @@ SetupPage { anchors.left: parent.left anchors.leftMargin: 40 - text_value: API.get().empty_string + (model.modelData) + text_value: API.get().settings_pg.empty_string + (model.modelData) anchors.verticalCenter: parent.verticalCenter font.pixelSize: Style.textSizeSmall2 } diff --git a/atomic_qt_design/qml/Screens/InitialLoading.qml b/atomic_qt_design/qml/Screens/InitialLoading.qml index 0eec4517aa..e0901fc0f0 100644 --- a/atomic_qt_design/qml/Screens/InitialLoading.qml +++ b/atomic_qt_design/qml/Screens/InitialLoading.qml @@ -28,7 +28,7 @@ SetupPage { content: ColumnLayout { DefaultText { - text_value: API.get().empty_string + (qsTr("Loading, please wait")) + text_value: API.get().settings_pg.empty_string + (qsTr("Loading, please wait")) Layout.bottomMargin: 10 } @@ -41,7 +41,7 @@ SetupPage { } DefaultText { - text_value: API.get().empty_string + ((API.get().initial_loading_status === "initializing_mm2" ? qsTr("Initializing MM2") : + text_value: API.get().settings_pg.empty_string + ((API.get().initial_loading_status === "initializing_mm2" ? qsTr("Initializing MM2") : API.get().initial_loading_status === "enabling_coins" ? qsTr("Enabling coins") : API.get().initial_loading_status === "complete" ? qsTr("Complete") : "") + "...") } diff --git a/atomic_qt_design/qml/Screens/Login.qml b/atomic_qt_design/qml/Screens/Login.qml index 09edf59f53..8d634da99c 100644 --- a/atomic_qt_design/qml/Screens/Login.qml +++ b/atomic_qt_design/qml/Screens/Login.qml @@ -24,7 +24,7 @@ SetupPage { } else { console.log("Failed: Login") - text_error = API.get().empty_string + (qsTr("Failed to login")) + text_error = API.get().settings_pg.empty_string + (qsTr("Failed to login")) return false } } @@ -52,7 +52,7 @@ SetupPage { width: 400 DefaultText { - text_value: API.get().empty_string + (qsTr("Login") + ": " + selected_wallet_name) + text_value: API.get().settings_pg.empty_string + (qsTr("Login") + ": " + selected_wallet_name) } HorizontalLine { @@ -69,7 +69,7 @@ SetupPage { spacing: Style.buttonSpacing DefaultButton { - text: API.get().empty_string + (qsTr("Back")) + text: API.get().settings_pg.empty_string + (qsTr("Back")) Layout.fillWidth: true onClicked: { reset() @@ -80,14 +80,14 @@ SetupPage { PrimaryButton { id: submit_button Layout.fillWidth: true - text: API.get().empty_string + (qsTr("Login")) + text: API.get().settings_pg.empty_string + (qsTr("Login")) onClicked: trySubmit() enabled: input_password.isValid() } } DefaultText { - text_value: API.get().empty_string + (text_error) + text_value: API.get().settings_pg.empty_string + (text_error) color: Style.colorRed visible: text !== '' } diff --git a/atomic_qt_design/qml/Screens/NewUser.qml b/atomic_qt_design/qml/Screens/NewUser.qml index a97d517b50..853a11c187 100644 --- a/atomic_qt_design/qml/Screens/NewUser.qml +++ b/atomic_qt_design/qml/Screens/NewUser.qml @@ -49,7 +49,7 @@ SetupPage { guess_text_error = "" } else { - guess_text_error = API.get().empty_string + (qsTr("Wrong word, please check again")) + guess_text_error = API.get().settings_pg.empty_string + (qsTr("Wrong word, please check again")) } } @@ -83,7 +83,7 @@ SetupPage { } else { console.log("Failed: Create wallet") - text_error = API.get().empty_string + (qsTr("Failed to create a wallet")) + text_error = API.get().settings_pg.empty_string + (qsTr("Failed to create a wallet")) return false } } @@ -97,7 +97,7 @@ SetupPage { spacing: Style.rowSpacing DefaultText { - text_value: API.get().empty_string + (qsTr("New User")) + text_value: API.get().settings_pg.empty_string + (qsTr("New User")) } HorizontalLine { @@ -149,7 +149,7 @@ SetupPage { TextAreaWithTitle { id: input_generated_seed - title: API.get().empty_string + (qsTr("Generated Seed")) + title: API.get().settings_pg.empty_string + (qsTr("Generated Seed")) field.text: current_mnemonic field.readOnly: true copyable: true @@ -175,14 +175,14 @@ SetupPage { width: parent.width - 40 horizontalAlignment: Text.AlignHCenter anchors.horizontalCenter: parent.horizontalCenter - text_value: API.get().empty_string + (qsTr("Important: Back up your seed phrase before proceeding!")) + text_value: API.get().settings_pg.empty_string + (qsTr("Important: Back up your seed phrase before proceeding!")) } DefaultText { width: parent.width - 40 horizontalAlignment: Text.AlignHCenter anchors.horizontalCenter: parent.horizontalCenter - text_value: API.get().empty_string + (qsTr("We recommend storing it offline.")) + text_value: API.get().settings_pg.empty_string + (qsTr("We recommend storing it offline.")) font.pixelSize: Style.textSizeSmall4 color: Style.colorWhite4 } @@ -191,8 +191,8 @@ SetupPage { TextAreaWithTitle { id: input_confirm_seed - title: API.get().empty_string + (qsTr("Confirm Seed")) - field.placeholderText: API.get().empty_string + (qsTr("Enter the generated seed here")) + title: API.get().settings_pg.empty_string + (qsTr("Confirm Seed")) + field.placeholderText: API.get().settings_pg.empty_string + (qsTr("Enter the generated seed here")) onReturn: completeForm } @@ -208,7 +208,7 @@ SetupPage { DefaultButton { Layout.fillWidth: true - text: API.get().empty_string + (qsTr("Back")) + text: API.get().settings_pg.empty_string + (qsTr("Back")) onClicked: { reset() onClickedBack() @@ -218,7 +218,7 @@ SetupPage { PrimaryButton { id: continue_button Layout.fillWidth: true - text: API.get().empty_string + (qsTr("Continue")) + text: API.get().settings_pg.empty_string + (qsTr("Continue")) onClicked: completeForm() enabled: // Fields are not empty input_wallet_name.field.acceptableInput === true && @@ -229,7 +229,7 @@ SetupPage { } DefaultText { - text_value: API.get().empty_string + (text_error) + text_value: API.get().settings_pg.empty_string + (text_error) color: Style.colorRed visible: text !== '' } @@ -257,13 +257,13 @@ SetupPage { DefaultText { width: parent.width - 40 anchors.horizontalCenter: parent.horizontalCenter - text_value: API.get().empty_string + (qsTr("Let's double check your seed phrase")) + text_value: API.get().settings_pg.empty_string + (qsTr("Let's double check your seed phrase")) } DefaultText { width: parent.width - 40 anchors.horizontalCenter: parent.horizontalCenter - text_value: API.get().empty_string + (qsTr("Your seed phrase is important - that's why we like to make sure it's correct. We'll ask you three different questions about your seed phrase to make sure you'll be able to easily restore your wallet whenever you want.")) + text_value: API.get().settings_pg.empty_string + (qsTr("Your seed phrase is important - that's why we like to make sure it's correct. We'll ask you three different questions about your seed phrase to make sure you'll be able to easily restore your wallet whenever you want.")) font.pixelSize: Style.textSizeSmall4 color: Style.colorWhite4 } @@ -273,8 +273,8 @@ SetupPage { TextFieldWithTitle { id: input_seed_word - title: API.get().empty_string + (qsTr("What's the %n. word in your seed phrase?", "", current_word_idx + 1)) - field.placeholderText: API.get().empty_string + (qsTr("Enter the %n. word", "", current_word_idx + 1)) + title: API.get().settings_pg.empty_string + (qsTr("What's the %n. word in your seed phrase?", "", current_word_idx + 1)) + field.placeholderText: API.get().settings_pg.empty_string + (qsTr("Enter the %n. word", "", current_word_idx + 1)) field.validator: RegExpValidator { regExp: /[a-z]+/ } field.onAccepted: tryGuess() } @@ -282,21 +282,21 @@ SetupPage { RowLayout { DefaultButton { Layout.fillWidth: true - text: API.get().empty_string + (qsTr("Go back and check again")) + text: API.get().settings_pg.empty_string + (qsTr("Go back and check again")) onClicked: form_is_filled = false } PrimaryButton { id: submit_button Layout.fillWidth: true - text: API.get().empty_string + (qsTr("Continue")) + text: API.get().settings_pg.empty_string + (qsTr("Continue")) onClicked: tryGuess() enabled: validGuessField(input_seed_word.field) } } DefaultText { - text_value: API.get().empty_string + (guess_text_error) + text_value: API.get().settings_pg.empty_string + (guess_text_error) color: Style.colorRed visible: text !== '' } diff --git a/atomic_qt_design/qml/Screens/RecoverSeed.qml b/atomic_qt_design/qml/Screens/RecoverSeed.qml index 6648ce0d32..f87723af25 100644 --- a/atomic_qt_design/qml/Screens/RecoverSeed.qml +++ b/atomic_qt_design/qml/Screens/RecoverSeed.qml @@ -25,7 +25,7 @@ SetupPage { } else { console.log("Failed: Recover seed") - text_error = API.get().empty_string + (qsTr("Failed to recover the seed")) + text_error = API.get().settings_pg.empty_string + (qsTr("Failed to recover the seed")) return false } } @@ -42,7 +42,7 @@ SetupPage { spacing: Style.rowSpacing DefaultText { - text_value: API.get().empty_string + (qsTr("Recovery")) + text_value: API.get().settings_pg.empty_string + (qsTr("Recovery")) } HorizontalLine { @@ -80,8 +80,8 @@ SetupPage { TextFieldWithTitle { id: input_seed_hidden visible: !input_seed.visible - title: API.get().empty_string + (qsTr("Seed")) - field.placeholderText: API.get().empty_string + (qsTr("Enter the seed")) + title: API.get().settings_pg.empty_string + (qsTr("Seed")) + field.placeholderText: API.get().settings_pg.empty_string + (qsTr("Enter the seed")) field.onTextChanged: { input_seed.field.text = field.text } @@ -99,8 +99,8 @@ SetupPage { TextAreaWithTitle { id: input_seed visible: false - title: API.get().empty_string + (qsTr("Seed")) - field.placeholderText: API.get().empty_string + (qsTr("Enter the seed")) + title: API.get().settings_pg.empty_string + (qsTr("Seed")) + field.placeholderText: API.get().settings_pg.empty_string + (qsTr("Enter the seed")) field.onTextChanged: { input_seed_hidden.field.text = field.text } @@ -117,7 +117,7 @@ SetupPage { DefaultCheckBox { id: allow_custom_seed - text: API.get().empty_string + (qsTr("Allow custom seed")) + text: API.get().settings_pg.empty_string + (qsTr("Allow custom seed")) } PasswordForm { @@ -132,7 +132,7 @@ SetupPage { DefaultButton { Layout.fillWidth: true - text: API.get().empty_string + (qsTr("Back")) + text: API.get().settings_pg.empty_string + (qsTr("Back")) onClicked: { reset() onClickedBack() @@ -142,7 +142,7 @@ SetupPage { PrimaryButton { id: submit_button Layout.fillWidth: true - text: API.get().empty_string + (qsTr("Confirm")) + text: API.get().settings_pg.empty_string + (qsTr("Confirm")) onClicked: trySubmit() enabled: // Fields are not empty input_wallet_name.field.acceptableInput === true && @@ -153,7 +153,7 @@ SetupPage { } DefaultText { - text_value: API.get().empty_string + (text_error) + text_value: API.get().settings_pg.empty_string + (text_error) color: Style.colorRed visible: text !== '' } diff --git a/atomic_qt_design/qml/Settings/DeleteWalletModal.qml b/atomic_qt_design/qml/Settings/DeleteWalletModal.qml index 77e1026cc2..2fc15859b9 100644 --- a/atomic_qt_design/qml/Settings/DeleteWalletModal.qml +++ b/atomic_qt_design/qml/Settings/DeleteWalletModal.qml @@ -24,7 +24,7 @@ DefaultModal { width: parent.width ModalHeader { - title: API.get().empty_string + (qsTr("Delete Wallet")) + title: API.get().settings_pg.empty_string + (qsTr("Delete Wallet")) } FloatingBackground { @@ -43,14 +43,14 @@ DefaultModal { DefaultText { Layout.alignment: Qt.AlignHCenter - text_value: API.get().empty_string + (qsTr("Are you sure you want to delete %1 wallet?", "WALLET_NAME").arg(API.get().wallet_default_name)) + text_value: API.get().settings_pg.empty_string + (qsTr("Are you sure you want to delete %1 wallet?", "WALLET_NAME").arg(API.get().wallet_default_name)) font.pixelSize: Style.textSize2 } DefaultText { Layout.alignment: Qt.AlignHCenter - text_value: API.get().empty_string + (qsTr("If so, make sure you record your seed phrase in order to restore your wallet in future.")) + text_value: API.get().settings_pg.empty_string + (qsTr("If so, make sure you record your seed phrase in order to restore your wallet in future.")) } } } @@ -59,11 +59,11 @@ DefaultModal { id: input_password Layout.fillWidth: true confirm: false - field.placeholderText: API.get().empty_string + (qsTr("Enter the password of your wallet")) + field.placeholderText: API.get().settings_pg.empty_string + (qsTr("Enter the password of your wallet")) } DefaultText { - text_value: API.get().empty_string + (qsTr("Wrong Password")) + text_value: API.get().settings_pg.empty_string + (qsTr("Wrong Password")) color: Style.colorRed visible: wrong_password } @@ -71,13 +71,13 @@ DefaultModal { // Buttons RowLayout { DefaultButton { - text: API.get().empty_string + (qsTr("Cancel")) + text: API.get().settings_pg.empty_string + (qsTr("Cancel")) Layout.fillWidth: true onClicked: root.close() } DangerButton { - text: API.get().empty_string + (qsTr("Delete")) + text: API.get().settings_pg.empty_string + (qsTr("Delete")) Layout.fillWidth: true enabled: input_password.isValid() onClicked: { diff --git a/atomic_qt_design/qml/Settings/Languages.qml b/atomic_qt_design/qml/Settings/Languages.qml index 250150a647..7647e0bfec 100644 --- a/atomic_qt_design/qml/Settings/Languages.qml +++ b/atomic_qt_design/qml/Settings/Languages.qml @@ -12,7 +12,7 @@ ColumnLayout { spacing: 20 DefaultText { Layout.alignment: Qt.AlignVCenter - text_value: API.get().empty_string + (qsTr("Language") + ":") + text_value: API.get().settings_pg.empty_string + (qsTr("Language") + ":") font.pixelSize: Style.textSizeSmall2 } @@ -27,11 +27,11 @@ ColumnLayout { layoutDirection: Qt.LeftToRight Repeater { - model: API.get().get_available_langs() + model: API.get().settings_pg.get_available_langs() delegate: Rectangle { width: image.sourceSize.width - 4 // Current icons have too much space around them height: image.sourceSize.height - 2 - color: API.get().lang === model.modelData ? Style.colorTheme11 : "transparent" + color: API.get().settings_pg.lang === model.modelData ? Style.colorTheme11 : "transparent" DefaultImage { id: image @@ -45,7 +45,7 @@ ColumnLayout { anchors.fill: parent acceptedButtons: Qt.LeftButton | Qt.RightButton onClicked: { - API.get().lang = model.modelData + API.get().settings_pg.lang = model.modelData } } } diff --git a/atomic_qt_design/qml/Settings/RecoverSeedModal.qml b/atomic_qt_design/qml/Settings/RecoverSeedModal.qml index bf566ed409..6409584e09 100644 --- a/atomic_qt_design/qml/Settings/RecoverSeedModal.qml +++ b/atomic_qt_design/qml/Settings/RecoverSeedModal.qml @@ -40,7 +40,7 @@ DefaultModal { width: parent.width ModalHeader { - title: API.get().empty_string + (qsTr("View Seed")) + title: API.get().settings_pg.empty_string + (qsTr("View Seed")) } ColumnLayout { @@ -51,7 +51,7 @@ DefaultModal { Layout.bottomMargin: 10 Layout.alignment: Qt.AlignHCenter - text_value: API.get().empty_string + (qsTr("Please enter your password to view the seed.")) + text_value: API.get().settings_pg.empty_string + (qsTr("Please enter your password to view the seed.")) } PasswordForm { @@ -62,7 +62,7 @@ DefaultModal { } DefaultText { - text_value: API.get().empty_string + (qsTr("Wrong Password")) + text_value: API.get().settings_pg.empty_string + (qsTr("Wrong Password")) color: Style.colorRed visible: wrong_password } @@ -71,7 +71,7 @@ DefaultModal { TextAreaWithTitle { visible: seed !== '' - title: API.get().empty_string + (qsTr("Seed")) + title: API.get().settings_pg.empty_string + (qsTr("Seed")) field.text: seed field.readOnly: true copyable: true @@ -80,7 +80,7 @@ DefaultModal { // Buttons RowLayout { DefaultButton { - text: API.get().empty_string + (seed === '' ? qsTr("Cancel") : qsTr("Close")) + text: API.get().settings_pg.empty_string + (seed === '' ? qsTr("Cancel") : qsTr("Close")) Layout.fillWidth: true onClicked: root.close() } @@ -88,7 +88,7 @@ DefaultModal { PrimaryButton { id: submit_button visible: seed === '' - text: API.get().empty_string + (qsTr("View")) + text: API.get().settings_pg.empty_string + (qsTr("View")) Layout.fillWidth: true enabled: input_password.isValid() onClicked: tryViewSeed() diff --git a/atomic_qt_design/qml/Settings/Settings.qml b/atomic_qt_design/qml/Settings/Settings.qml index cca1932085..b865b62096 100644 --- a/atomic_qt_design/qml/Settings/Settings.qml +++ b/atomic_qt_design/qml/Settings/Settings.qml @@ -22,7 +22,7 @@ Item { } property string mm2_version: '' - property var fiats: API.get().get_available_fiats() + property var fiats: API.get().settings_pg.get_available_fiats() InnerBackground { id: layout_background @@ -38,7 +38,7 @@ Item { ComboBoxWithTitle { id: combo_fiat - title: API.get().empty_string + (qsTr("Fiat")) + title: API.get().settings_pg.empty_string + (qsTr("Fiat")) Layout.fillWidth: true field.model: fiats @@ -47,12 +47,12 @@ Item { field.onCurrentIndexChanged: { if(initialized) { const new_fiat = fiats[field.currentIndex] - API.get().current_fiat = new_fiat - API.get().current_currency = new_fiat + API.get().settings_pg.current_fiat = new_fiat + API.get().settings_pg.current_currency = new_fiat } } Component.onCompleted: { - field.currentIndex = field.model.indexOf(API.get().current_fiat) + field.currentIndex = field.model.indexOf(API.get().settings_pg.current_fiat) initialized = true } } @@ -68,14 +68,14 @@ Item { Switch { Layout.alignment: Qt.AlignHCenter - text: API.get().empty_string + (qsTr("Enable Desktop Notifications")) + text: API.get().settings_pg.empty_string + (qsTr("Enable Desktop Notifications")) Component.onCompleted: checked = General.enable_desktop_notifications onCheckedChanged: General.enable_desktop_notifications = checked } DefaultButton { Layout.fillWidth: true - text: API.get().empty_string + (qsTr("Open Logs Folder")) + text: API.get().settings_pg.empty_string + (qsTr("Open Logs Folder")) onClicked: { API.get().export_swaps_json() const prefix = Qt.platform.os == "windows" ? "file:///" : "file://" @@ -85,7 +85,7 @@ Item { DefaultButton { Layout.fillWidth: true - text: API.get().empty_string + (qsTr("View Seed")) + text: API.get().settings_pg.empty_string + (qsTr("View Seed")) onClicked: recover_seed_modal.open() } @@ -99,7 +99,7 @@ Item { DefaultButton { Layout.fillWidth: true - text: API.get().empty_string + (qsTr("Disclaimer and ToS")) + text: API.get().settings_pg.empty_string + (qsTr("Disclaimer and ToS")) onClicked: eula.open() } @@ -113,7 +113,7 @@ Item { } DangerButton { - text: API.get().empty_string + (qsTr("Delete Wallet")) + text: API.get().settings_pg.empty_string + (qsTr("Delete Wallet")) Layout.fillWidth: true onClicked: delete_wallet_modal.open() } @@ -124,7 +124,7 @@ Item { DefaultButton { Layout.fillWidth: true - text: API.get().empty_string + (qsTr("Log out")) + text: API.get().settings_pg.empty_string + (qsTr("Log out")) onClicked: disconnect() } } @@ -135,7 +135,7 @@ Item { anchors.bottom: parent.bottom anchors.bottomMargin: 10 anchors.rightMargin: anchors.bottomMargin - text_value: API.get().empty_string + (qsTr("mm2 version") + ": " + mm2_version) + text_value: API.get().settings_pg.empty_string + (qsTr("mm2 version") + ": " + mm2_version) font.pixelSize: Style.textSizeSmall } } diff --git a/atomic_qt_design/qml/Sidebar/Sidebar.qml b/atomic_qt_design/qml/Sidebar/Sidebar.qml index 7cd30243ca..d8196587a8 100644 --- a/atomic_qt_design/qml/Sidebar/Sidebar.qml +++ b/atomic_qt_design/qml/Sidebar/Sidebar.qml @@ -141,7 +141,7 @@ Item { anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top anchors.topMargin: parent.width * 0.85 - text_value: API.get().empty_string + ("V. AtomicDEX PRO " + API.get().get_version()) + text_value: API.get().settings_pg.empty_string + ("V. AtomicDEX PRO " + API.get().get_version()) font.pixelSize: Style.textSizeVerySmall8 color: Style.colorThemeDarkLight } diff --git a/atomic_qt_design/qml/Sidebar/SidebarBottom.qml b/atomic_qt_design/qml/Sidebar/SidebarBottom.qml index c5aba01cd4..9e12d7f714 100644 --- a/atomic_qt_design/qml/Sidebar/SidebarBottom.qml +++ b/atomic_qt_design/qml/Sidebar/SidebarBottom.qml @@ -12,7 +12,7 @@ ColumnLayout { SidebarLine { dashboard_index: General.idx_dashboard_settings - text_value: API.get().empty_string + (qsTr("Settings")) + text_value: API.get().settings_pg.empty_string + (qsTr("Settings")) image: General.image_path + "menu-settings-white.svg" Layout.fillWidth: true separator: false @@ -20,7 +20,7 @@ ColumnLayout { SidebarLine { dashboard_index: General.idx_dashboard_privacy_mode - text_value: API.get().empty_string + (qsTr("Privacy")) + text_value: API.get().settings_pg.empty_string + (qsTr("Privacy")) image: "" Layout.fillWidth: true separator: false @@ -29,7 +29,7 @@ ColumnLayout { // SidebarLine { // dashboard_index: General.idx_dashboard_light_ui -// text_value: API.get().empty_string + (qsTr("Light UI")) +// text_value: API.get().settings_pg.empty_string + (qsTr("Light UI")) // image: "" // Layout.fillWidth: true // separator: false diff --git a/atomic_qt_design/qml/Sidebar/SidebarCenter.qml b/atomic_qt_design/qml/Sidebar/SidebarCenter.qml index 7d24312975..cf9f44a7c6 100644 --- a/atomic_qt_design/qml/Sidebar/SidebarCenter.qml +++ b/atomic_qt_design/qml/Sidebar/SidebarCenter.qml @@ -12,7 +12,7 @@ ColumnLayout { SidebarLine { dashboard_index: General.idx_dashboard_portfolio - text_value: API.get().empty_string + (qsTr("Dashboard")) + text_value: API.get().settings_pg.empty_string + (qsTr("Dashboard")) image: General.image_path + "menu-assets-portfolio.svg" Layout.fillWidth: true separator: false @@ -20,28 +20,28 @@ ColumnLayout { SidebarLine { dashboard_index: General.idx_dashboard_wallet - text_value: API.get().empty_string + (qsTr("Wallet")) + text_value: API.get().settings_pg.empty_string + (qsTr("Wallet")) image: General.image_path + "menu-assets-white.svg" Layout.fillWidth: true } SidebarLine { dashboard_index: General.idx_dashboard_exchange - text_value: API.get().empty_string + (qsTr("DEX")) + text_value: API.get().settings_pg.empty_string + (qsTr("DEX")) image: General.image_path + "menu-exchange-white.svg" Layout.fillWidth: true } SidebarLine { dashboard_index: General.idx_dashboard_news - text_value: API.get().empty_string + (qsTr("News")) + text_value: API.get().settings_pg.empty_string + (qsTr("News")) image: General.image_path + "menu-news-white.svg" Layout.fillWidth: true } SidebarLine { dashboard_index: General.idx_dashboard_dapps - text_value: API.get().empty_string + (qsTr("Dapps")) + text_value: API.get().settings_pg.empty_string + (qsTr("Dapps")) image: General.image_path + "menu-dapp-white.svg" Layout.fillWidth: true } diff --git a/atomic_qt_design/qml/Wallet/AddressBook.qml b/atomic_qt_design/qml/Wallet/AddressBook.qml index ea79b97bfe..db71b3b6c5 100644 --- a/atomic_qt_design/qml/Wallet/AddressBook.qml +++ b/atomic_qt_design/qml/Wallet/AddressBook.qml @@ -45,7 +45,7 @@ ColumnLayout { id: back_button property bool disabled: global_edit_in_progress Layout.leftMargin: layout_margin - text_value: API.get().empty_string + ("< " + qsTr("Back")) + text_value: API.get().settings_pg.empty_string + ("< " + qsTr("Back")) font.bold: true color: disabled ? Style.colorTextDisabled : Style.colorText @@ -60,7 +60,7 @@ ColumnLayout { Layout.fillWidth: true DefaultText { - text_value: API.get().empty_string + (qsTr("Address Book")) + text_value: API.get().settings_pg.empty_string + (qsTr("Address Book")) font.bold: true font.pixelSize: Style.textSize3 Layout.fillWidth: true @@ -69,7 +69,7 @@ ColumnLayout { DefaultButton { Layout.rightMargin: layout_margin Layout.alignment: Qt.AlignRight - text: API.get().empty_string + (qsTr("New Contact")) + text: API.get().settings_pg.empty_string + (qsTr("New Contact")) enabled: !global_edit_in_progress onClicked: { API.get().addressbook_mdl.add_contact_entry() @@ -169,7 +169,7 @@ ColumnLayout { id: name_input color: Style.colorText - placeholderText: API.get().empty_string + (qsTr("Enter the contact name")) + placeholderText: API.get().settings_pg.empty_string + (qsTr("Enter the contact name")) width: 150 onTextChanged: { const max_length = 50 @@ -367,7 +367,7 @@ ColumnLayout { anchors.verticalCenter: parent.verticalCenter visible: !combo_base.visible - text_value: API.get().empty_string + (type) + text_value: API.get().settings_pg.empty_string + (type) } DefaultComboBox { @@ -410,7 +410,7 @@ ColumnLayout { anchors.verticalCenter: parent.verticalCenter anchors.leftMargin: layout_margin * 7 font.pixelSize: Style.textSizeSmall3 - placeholderText: API.get().empty_string + (qsTr("Enter the address")) + placeholderText: API.get().settings_pg.empty_string + (qsTr("Enter the address")) width: 400 visible: editing_address } @@ -439,7 +439,7 @@ ColumnLayout { Layout.leftMargin: layout_margin font.pixelSize: Style.textSizeSmall3 - text: API.get().empty_string + (qsTr("Explorer")) + text: API.get().settings_pg.empty_string + (qsTr("Explorer")) enabled: address !== "" && type !== "" visible: !editing_address onClicked: General.viewAddressAtExplorer(type, address) @@ -450,7 +450,7 @@ ColumnLayout { Layout.leftMargin: layout_margin font.pixelSize: Style.textSizeSmall3 - text: API.get().empty_string + (qsTr("Send")) + text: API.get().settings_pg.empty_string + (qsTr("Send")) minWidth: height enabled: address !== "" && type !== "" && API.get().enabled_coins.map(c => c.ticker).indexOf(type) !== -1 visible: !editing_address diff --git a/atomic_qt_design/qml/Wallet/AddressList.qml b/atomic_qt_design/qml/Wallet/AddressList.qml index 0724eb7783..3228be5814 100644 --- a/atomic_qt_design/qml/Wallet/AddressList.qml +++ b/atomic_qt_design/qml/Wallet/AddressList.qml @@ -25,7 +25,7 @@ ColumnLayout { // Row delegate: DefaultText { - text_value: API.get().empty_string + (model.modelData) + text_value: API.get().settings_pg.empty_string + (model.modelData) color: Style.modalValueColor privacy: true } diff --git a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml index 1f0c704ed8..07f42fb099 100644 --- a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml +++ b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml @@ -62,12 +62,12 @@ DefaultModal { Layout.fillWidth: true ModalHeader { - title: API.get().empty_string + (qsTr("Claim your %1 reward?", "TICKER").arg(API.get().current_coin_info.ticker)) + title: API.get().settings_pg.empty_string + (qsTr("Claim your %1 reward?", "TICKER").arg(API.get().current_coin_info.ticker)) } DefaultText { visible: text_error.text === "" - text_value: API.get().empty_string + (qsTr("You will receive %1", "AMT TICKER").arg(General.formatCrypto("", prepare_claim_rewards_result.balance_change, API.get().current_coin_info.ticker))) + text_value: API.get().settings_pg.empty_string + (qsTr("You will receive %1", "AMT TICKER").arg(General.formatCrypto("", prepare_claim_rewards_result.balance_change, API.get().current_coin_info.ticker))) } DefaultText { @@ -79,12 +79,12 @@ DefaultModal { // Buttons RowLayout { DefaultButton { - text: API.get().empty_string + (qsTr("Cancel")) + text: API.get().settings_pg.empty_string + (qsTr("Cancel")) Layout.fillWidth: true onClicked: root.close() } PrimaryButton { - text: API.get().empty_string + (qsTr("Confirm")) + text: API.get().settings_pg.empty_string + (qsTr("Confirm")) Layout.fillWidth: true onClicked: claimRewards() } diff --git a/atomic_qt_design/qml/Wallet/CoinList.qml b/atomic_qt_design/qml/Wallet/CoinList.qml index b9a9b277bc..4c60a3398b 100644 --- a/atomic_qt_design/qml/Wallet/CoinList.qml +++ b/atomic_qt_design/qml/Wallet/CoinList.qml @@ -26,7 +26,7 @@ Column { id: utxo_list delegate: DefaultCheckBox { - text: API.get().empty_string + " " + (model.modelData.name + " (" + model.modelData.ticker + ")") + text: API.get().settings_pg.empty_string + " " + (model.modelData.name + " (" + model.modelData.ticker + ")") leftPadding: indicator.width ButtonGroup.group: childGroup diff --git a/atomic_qt_design/qml/Wallet/EnableCoinModal.qml b/atomic_qt_design/qml/Wallet/EnableCoinModal.qml index 3c07984c0f..10b0765c99 100644 --- a/atomic_qt_design/qml/Wallet/EnableCoinModal.qml +++ b/atomic_qt_design/qml/Wallet/EnableCoinModal.qml @@ -56,7 +56,7 @@ DefaultModal { ColumnLayout { id: modal_layout ModalHeader { - title: API.get().empty_string + (qsTr("Enable coins")) + title: API.get().settings_pg.empty_string + (qsTr("Enable coins")) } // Search input @@ -64,7 +64,7 @@ DefaultModal { id: input_coin_filter Layout.fillWidth: true - placeholderText: API.get().empty_string + (qsTr("Search")) + placeholderText: API.get().settings_pg.empty_string + (qsTr("Search")) selectByMouse: true } @@ -80,19 +80,19 @@ DefaultModal { CoinList { id: coins_utxo - group_title: API.get().empty_string + qsTr("Select all UTXO coins") + group_title: API.get().settings_pg.empty_string + qsTr("Select all UTXO coins") model: General.filterCoins(API.get().enableable_coins, input_coin_filter.text, "UTXO") } CoinList { id: coins_smartchains - group_title: API.get().empty_string + qsTr("Select all SmartChains") + group_title: API.get().settings_pg.empty_string + qsTr("Select all SmartChains") model: General.filterCoins(API.get().enableable_coins, input_coin_filter.text, "Smart Chain") } CoinList { id: coins_erc - group_title: API.get().empty_string + qsTr("Select all ERC tokens") + group_title: API.get().settings_pg.empty_string + qsTr("Select all ERC tokens") model: General.filterCoins(API.get().enableable_coins, input_coin_filter.text, "ERC-20") } } @@ -103,20 +103,20 @@ DefaultModal { DefaultText { visible: API.get().enableable_coins.length === 0 - text_value: API.get().empty_string + (qsTr("All coins are already enabled!")) + text_value: API.get().settings_pg.empty_string + (qsTr("All coins are already enabled!")) } // Buttons RowLayout { DefaultButton { - text: API.get().empty_string + (qsTr("Close")) + text: API.get().settings_pg.empty_string + (qsTr("Close")) Layout.fillWidth: true onClicked: root.close() } PrimaryButton { visible: API.get().enableable_coins.length > 0 enabled: Object.keys(selected_to_enable).length > 0 - text: API.get().empty_string + (qsTr("Enable")) + text: API.get().settings_pg.empty_string + (qsTr("Enable")) Layout.fillWidth: true onClicked: enableCoins() } diff --git a/atomic_qt_design/qml/Wallet/Main.qml b/atomic_qt_design/qml/Wallet/Main.qml index 534eda5b6b..455bcd0317 100644 --- a/atomic_qt_design/qml/Wallet/Main.qml +++ b/atomic_qt_design/qml/Wallet/Main.qml @@ -77,14 +77,14 @@ Item { DefaultText { id: name - text_value: API.get().empty_string + (API.get().current_coin_info.name) + text_value: API.get().settings_pg.empty_string + (API.get().current_coin_info.name) Layout.alignment: Qt.AlignLeft font.pixelSize: Style.textSizeMid } DefaultText { id: name_value - text_value: API.get().empty_string + (General.formatCrypto("", API.get().current_coin_info.balance, API.get().current_coin_info.ticker)) + text_value: API.get().settings_pg.empty_string + (General.formatCrypto("", API.get().current_coin_info.balance, API.get().current_coin_info.ticker)) Layout.alignment: Qt.AlignLeft font.pixelSize: name.font.pixelSize privacy: true @@ -97,14 +97,14 @@ Item { Layout.alignment: Qt.AlignLeft spacing: balance_layout.spacing DefaultText { - text_value: API.get().empty_string + (qsTr("Wallet Balance")) + text_value: API.get().settings_pg.empty_string + (qsTr("Wallet Balance")) Layout.alignment: Qt.AlignLeft font.pixelSize: name.font.pixelSize color: price.color } DefaultText { - text_value: API.get().empty_string + (General.formatFiat("", API.get().current_coin_info.fiat_amount, API.get().current_currency)) + text_value: API.get().settings_pg.empty_string + (General.formatFiat("", API.get().current_coin_info.fiat_amount, API.get().settings_pg.current_currency)) Layout.alignment: Qt.AlignLeft font.pixelSize: name.font.pixelSize privacy: true @@ -124,14 +124,14 @@ Item { spacing: balance_layout.spacing DefaultText { id: price - text_value: API.get().empty_string + (qsTr("Price")) + text_value: API.get().settings_pg.empty_string + (qsTr("Price")) Layout.alignment: Qt.AlignLeft font.pixelSize: name.font.pixelSize color: Style.colorText2 } DefaultText { - text_value: API.get().empty_string + (General.formatFiat('', API.get().current_coin_info.main_currency_balance, API.get().current_currency)) + text_value: API.get().settings_pg.empty_string + (General.formatFiat('', API.get().current_coin_info.main_currency_balance, API.get().settings_pg.current_currency)) Layout.alignment: Qt.AlignLeft font.pixelSize: name.font.pixelSize } @@ -142,7 +142,7 @@ Item { Layout.alignment: Qt.AlignHCenter spacing: balance_layout.spacing DefaultText { - text_value: API.get().empty_string + (qsTr("Change 24h")) + text_value: API.get().settings_pg.empty_string + (qsTr("Change 24h")) Layout.alignment: Qt.AlignLeft font.pixelSize: name.font.pixelSize color: price.color @@ -151,7 +151,7 @@ Item { DefaultText { text_value: { const v = parseFloat(API.get().current_coin_info.change_24h) - return API.get().empty_string + (v === 0 ? '-' : General.formatPercent(v)) + return API.get().settings_pg.empty_string + (v === 0 ? '-' : General.formatPercent(v)) } Layout.alignment: Qt.AlignLeft font.pixelSize: name.font.pixelSize @@ -164,7 +164,7 @@ Item { Layout.alignment: Qt.AlignHCenter spacing: balance_layout.spacing DefaultText { - text_value: API.get().empty_string + (qsTr("Portfolio %")) + text_value: API.get().settings_pg.empty_string + (qsTr("Portfolio %")) Layout.alignment: Qt.AlignLeft font.pixelSize: name.font.pixelSize color: price.color @@ -176,7 +176,7 @@ Item { const portfolio_balance = parseFloat(API.get().balance_fiat_all) if(fiat_amount <= 0 || portfolio_balance <= 0) return "-" - return API.get().empty_string + (General.formatPercent((100 * fiat_amount/portfolio_balance).toFixed(2), false)) + return API.get().settings_pg.empty_string + (General.formatPercent((100 * fiat_amount/portfolio_balance).toFixed(2), false)) } Layout.alignment: Qt.AlignLeft font.pixelSize: name.font.pixelSize @@ -226,7 +226,7 @@ Item { DefaultText { id: left_text - text_value: API.get().empty_string + (qsTr("%1 / %2 Price", "TICKER").arg(API.get().current_coin_info.ticker).arg(API.get().current_fiat) + " " + General.cex_icon) + text_value: API.get().settings_pg.empty_string + (qsTr("%1 / %2 Price", "TICKER").arg(API.get().current_coin_info.ticker).arg(API.get().settings_pg.current_fiat) + " " + General.cex_icon) font.pixelSize: Style.textSizeSmall3 CexInfoTrigger {} @@ -250,7 +250,7 @@ Item { } DefaultText { - text_value: API.get().empty_string + (qsTr("Volume 24h") + " (" + API.get().current_fiat + ")") + text_value: API.get().settings_pg.empty_string + (qsTr("Volume 24h") + " (" + API.get().settings_pg.current_fiat + ")") font: left_text.font } } @@ -272,13 +272,13 @@ Item { spacing: 15 DefaultButton { - text: API.get().empty_string + (qsTr("Address Book")) + text: API.get().settings_pg.empty_string + (qsTr("Address Book")) onClicked: openAddressBook() } DefaultButton { enabled: parseFloat(API.get().current_coin_info.balance) > 0 - text: API.get().empty_string + (qsTr("Send")) + text: API.get().settings_pg.empty_string + (qsTr("Send")) onClicked: send_modal.open() text_offset: -arrow_send.anchors.rightMargin text_left_align: true @@ -298,7 +298,7 @@ Item { } DefaultButton { - text: API.get().empty_string + (qsTr("Receive")) + text: API.get().settings_pg.empty_string + (qsTr("Receive")) onClicked: receive_modal.open() text_offset: -arrow_send.anchors.rightMargin text_left_align: true @@ -317,7 +317,7 @@ Item { } DefaultButton { - text: API.get().empty_string + (qsTr("Swap")) + text: API.get().settings_pg.empty_string + (qsTr("Swap")) onClicked: onClickedSwap() text_offset: -arrow_send.anchors.rightMargin text_left_align: true @@ -341,7 +341,7 @@ Item { PrimaryButton { id: button_claim_rewards - text: API.get().empty_string + (qsTr("Claim Rewards")) + text: API.get().settings_pg.empty_string + (qsTr("Claim Rewards")) visible: API.get().current_coin_info.is_claimable === true enabled: claim_rewards_modal.canClaim() @@ -379,7 +379,7 @@ Item { anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter DefaultText { - text_value: API.get().empty_string + (qsTr("Loading")) + text_value: API.get().settings_pg.empty_string + (qsTr("Loading")) Layout.alignment: Qt.AlignHCenter font.pixelSize: Style.textSize2 } @@ -389,7 +389,7 @@ Item { } DefaultText { - text_value: API.get().empty_string + ( + text_value: API.get().settings_pg.empty_string + ( API.get().current_coin_info.type === "ERC-20" ? (qsTr("Scanning blocks for TX History...") + " " + loadingPercentage(API.get().current_coin_info.blocks_left)) : (qsTr("Syncing TX History...") + " " + loadingPercentage(API.get().current_coin_info.transactions_left)) @@ -423,7 +423,7 @@ Item { DefaultText { anchors.centerIn: parent visible: API.get().current_coin_info.tx_state !== "InProgress" && API.get().current_coin_info.transactions.length === 0 - text_value: API.get().empty_string + (qsTr("No transactions")) + text_value: API.get().settings_pg.empty_string + (qsTr("No transactions")) font.pixelSize: Style.textSize color: Style.colorWhite4 } diff --git a/atomic_qt_design/qml/Wallet/ReceiveModal.qml b/atomic_qt_design/qml/Wallet/ReceiveModal.qml index 9eb9b5e14b..236b97385a 100644 --- a/atomic_qt_design/qml/Wallet/ReceiveModal.qml +++ b/atomic_qt_design/qml/Wallet/ReceiveModal.qml @@ -18,13 +18,13 @@ DefaultModal { width: parent.width ModalHeader { - title: API.get().empty_string + (qsTr("Receive")) + title: API.get().settings_pg.empty_string + (qsTr("Receive")) } // Receive address TextAreaWithTitle { - title: API.get().empty_string + (qsTr("Share this address to receive coins")) - field.text: API.get().empty_string + (API.get().current_coin_info.address) + title: API.get().settings_pg.empty_string + (qsTr("Share this address to receive coins")) + field.text: API.get().settings_pg.empty_string + (API.get().current_coin_info.address) field.readOnly: true field.wrapMode: TextEdit.NoWrap copyable: true @@ -43,7 +43,7 @@ DefaultModal { // Buttons RowLayout { DefaultButton { - text: API.get().empty_string + (qsTr("Close")) + text: API.get().settings_pg.empty_string + (qsTr("Close")) Layout.fillWidth: true onClicked: root.close() } diff --git a/atomic_qt_design/qml/Wallet/SendModal.qml b/atomic_qt_design/qml/Wallet/SendModal.qml index 75d5c294a7..a5a5ffd8db 100644 --- a/atomic_qt_design/qml/Wallet/SendModal.qml +++ b/atomic_qt_design/qml/Wallet/SendModal.qml @@ -167,7 +167,7 @@ DefaultModal { Layout.fillWidth: true ModalHeader { - title: API.get().empty_string + (qsTr("Prepare to Send")) + title: API.get().settings_pg.empty_string + (qsTr("Prepare to Send")) } // Send address @@ -177,13 +177,13 @@ DefaultModal { AddressFieldWithTitle { id: input_address Layout.alignment: Qt.AlignLeft - title: API.get().empty_string + (qsTr("Recipient's address")) - field.placeholderText: API.get().empty_string + (qsTr("Enter address of the recipient")) + title: API.get().settings_pg.empty_string + (qsTr("Recipient's address")) + field.placeholderText: API.get().settings_pg.empty_string + (qsTr("Enter address of the recipient")) } DefaultButton { Layout.alignment: Qt.AlignRight | Qt.AlignBottom - text: API.get().empty_string + (qsTr("Address Book")) + text: API.get().settings_pg.empty_string + (qsTr("Address Book")) onClicked: { openAddressBook() root.close() @@ -198,12 +198,12 @@ DefaultModal { DefaultText { Layout.alignment: Qt.AlignLeft color: Style.colorRed - text_value: API.get().empty_string + (qsTr("The address has to be mixed case.")) + text_value: API.get().settings_pg.empty_string + (qsTr("The address has to be mixed case.")) } DefaultButton { Layout.alignment: Qt.AlignRight - text: API.get().empty_string + (qsTr("Fix")) + text: API.get().settings_pg.empty_string + (qsTr("Fix")) onClicked: input_address.field.text = ercToMixedCase(input_address.field.text) } } @@ -215,14 +215,14 @@ DefaultModal { AmountField { id: input_amount field.visible: !input_max_amount.checked - title: API.get().empty_string + (qsTr("Amount to send")) - field.placeholderText: API.get().empty_string + (qsTr("Enter the amount to send")) + title: API.get().settings_pg.empty_string + (qsTr("Amount to send")) + field.placeholderText: API.get().settings_pg.empty_string + (qsTr("Enter the amount to send")) } Switch { id: input_max_amount Layout.alignment: Qt.AlignRight | Qt.AlignBottom - text: API.get().empty_string + (qsTr("MAX")) + text: API.get().settings_pg.empty_string + (qsTr("MAX")) onCheckedChanged: input_amount.field.text = "" } } @@ -230,7 +230,7 @@ DefaultModal { // Custom fees switch Switch { id: custom_fees_switch - text: API.get().empty_string + (qsTr("Enable Custom Fees")) + text: API.get().settings_pg.empty_string + (qsTr("Enable Custom Fees")) onCheckedChanged: input_custom_fees.field.text = "" } @@ -241,7 +241,7 @@ DefaultModal { DefaultText { font.pixelSize: Style.textSize color: Style.colorRed - text_value: API.get().empty_string + (qsTr("Only use custom fees if you know what you are doing!")) + text_value: API.get().settings_pg.empty_string + (qsTr("Only use custom fees if you know what you are doing!")) } // Normal coins, Custom fees input @@ -249,8 +249,8 @@ DefaultModal { visible: !isERC20() id: input_custom_fees - title: API.get().empty_string + (qsTr("Custom Fee") + " [" + API.get().current_coin_info.ticker + "]") - field.placeholderText: API.get().empty_string + (qsTr("Enter the custom fee")) + title: API.get().settings_pg.empty_string + (qsTr("Custom Fee") + " [" + API.get().current_coin_info.ticker + "]") + field.placeholderText: API.get().settings_pg.empty_string + (qsTr("Enter the custom fee")) } // ERC-20 coins @@ -260,15 +260,15 @@ DefaultModal { // Gas input AmountIntField { id: input_custom_fees_gas - title: API.get().empty_string + (qsTr("Gas Limit") + " [Gwei]") - field.placeholderText: API.get().empty_string + (qsTr("Enter the gas limit")) + title: API.get().settings_pg.empty_string + (qsTr("Gas Limit") + " [Gwei]") + field.placeholderText: API.get().settings_pg.empty_string + (qsTr("Enter the gas limit")) } // Gas price input AmountIntField { id: input_custom_fees_gas_price - title: API.get().empty_string + (qsTr("Gas Price") + " [Gwei]") - field.placeholderText: API.get().empty_string + (qsTr("Enter the gas price")) + title: API.get().settings_pg.empty_string + (qsTr("Gas Price") + " [Gwei]") + field.placeholderText: API.get().settings_pg.empty_string + (qsTr("Enter the gas price")) } } } @@ -282,7 +282,7 @@ DefaultModal { color: Style.colorRed - text_value: API.get().empty_string + (qsTr("Custom Fee can't be higher than the amount")) + text_value: API.get().settings_pg.empty_string + (qsTr("Custom Fee can't be higher than the amount")) } // Not enough funds error @@ -292,7 +292,7 @@ DefaultModal { color: Style.colorRed - text_value: API.get().empty_string + (qsTr("Not enough funds.") + "\n" + qsTr("You have %1", "AMT TICKER").arg(General.formatCrypto("", API.get().get_balance(API.get().current_coin_info.ticker), API.get().current_coin_info.ticker))) + text_value: API.get().settings_pg.empty_string + (qsTr("Not enough funds.") + "\n" + qsTr("You have %1", "AMT TICKER").arg(General.formatCrypto("", API.get().get_balance(API.get().current_coin_info.ticker), API.get().current_coin_info.ticker))) } DefaultText { @@ -304,12 +304,12 @@ DefaultModal { // Buttons RowLayout { DefaultButton { - text: API.get().empty_string + (qsTr("Close")) + text: API.get().settings_pg.empty_string + (qsTr("Close")) Layout.fillWidth: true onClicked: root.close() } PrimaryButton { - text: API.get().empty_string + (qsTr("Prepare")) + text: API.get().settings_pg.empty_string + (qsTr("Prepare")) Layout.fillWidth: true enabled: fieldAreFilled() && hasFunds() && !hasErc20CaseIssue(isERC20(), input_address.field.text) @@ -323,42 +323,42 @@ DefaultModal { // Send Page ColumnLayout { ModalHeader { - title: API.get().empty_string + (qsTr("Send")) + title: API.get().settings_pg.empty_string + (qsTr("Send")) } // Address TextWithTitle { - title: API.get().empty_string + (qsTr("Recipient's address")) - text: API.get().empty_string + (input_address.field.text) + title: API.get().settings_pg.empty_string + (qsTr("Recipient's address")) + text: API.get().settings_pg.empty_string + (input_address.field.text) } // Amount TextWithTitle { - title: API.get().empty_string + (qsTr("Amount")) - text: API.get().empty_string + (General.formatCrypto("", input_amount.field.text, API.get().current_coin_info.ticker)) + title: API.get().settings_pg.empty_string + (qsTr("Amount")) + text: API.get().settings_pg.empty_string + (General.formatCrypto("", input_amount.field.text, API.get().current_coin_info.ticker)) } // Fees TextWithTitle { - title: API.get().empty_string + (qsTr("Fees")) - text: API.get().empty_string + (General.formatCrypto("", prepare_send_result.fees, General.txFeeTicker(API.get().current_coin_info))) + title: API.get().settings_pg.empty_string + (qsTr("Fees")) + text: API.get().settings_pg.empty_string + (General.formatCrypto("", prepare_send_result.fees, General.txFeeTicker(API.get().current_coin_info))) } // Date TextWithTitle { - title: API.get().empty_string + (qsTr("Date")) - text: API.get().empty_string + (prepare_send_result.date) + title: API.get().settings_pg.empty_string + (qsTr("Date")) + text: API.get().settings_pg.empty_string + (prepare_send_result.date) } // Buttons RowLayout { DefaultButton { - text: API.get().empty_string + (qsTr("Back")) + text: API.get().settings_pg.empty_string + (qsTr("Back")) Layout.fillWidth: true onClicked: stack_layout.currentIndex = 0 } PrimaryButton { - text: API.get().empty_string + (qsTr("Send")) + text: API.get().settings_pg.empty_string + (qsTr("Send")) Layout.fillWidth: true onClicked: sendCoin() } diff --git a/atomic_qt_design/qml/Wallet/SendResult.qml b/atomic_qt_design/qml/Wallet/SendResult.qml index e27e247aa7..bfdaad4e74 100644 --- a/atomic_qt_design/qml/Wallet/SendResult.qml +++ b/atomic_qt_design/qml/Wallet/SendResult.qml @@ -14,49 +14,49 @@ ColumnLayout { function onClose() {} ModalHeader { - title: API.get().empty_string + (qsTr("Transaction Complete!")) + title: API.get().settings_pg.empty_string + (qsTr("Transaction Complete!")) } // Address TextWithTitle { id: address - title: API.get().empty_string + (qsTr("Recipient's address")) + title: API.get().settings_pg.empty_string + (qsTr("Recipient's address")) visible: text !== "" } // Amount TextWithTitle { - title: API.get().empty_string + (qsTr("Amount")) - text: API.get().empty_string + (General.formatCrypto("", custom_amount !== "" ? custom_amount : result.balance_change, API.get().current_coin_info.ticker)) + title: API.get().settings_pg.empty_string + (qsTr("Amount")) + text: API.get().settings_pg.empty_string + (General.formatCrypto("", custom_amount !== "" ? custom_amount : result.balance_change, API.get().current_coin_info.ticker)) } // Fees TextWithTitle { - title: API.get().empty_string + (qsTr("Fees")) - text: API.get().empty_string + (General.formatCrypto("", result.fees, General.txFeeTicker(API.get().current_coin_info))) + title: API.get().settings_pg.empty_string + (qsTr("Fees")) + text: API.get().settings_pg.empty_string + (General.formatCrypto("", result.fees, General.txFeeTicker(API.get().current_coin_info))) } // Date TextWithTitle { - title: API.get().empty_string + (qsTr("Date")) - text: API.get().empty_string + (result.date) + title: API.get().settings_pg.empty_string + (qsTr("Date")) + text: API.get().settings_pg.empty_string + (result.date) } // Transaction Hash TextWithTitle { id: tx_hash - title: API.get().empty_string + (qsTr("Transaction Hash")) + title: API.get().settings_pg.empty_string + (qsTr("Transaction Hash")) } // Buttons RowLayout { DefaultButton { - text: API.get().empty_string + (qsTr("Close")) + text: API.get().settings_pg.empty_string + (qsTr("Close")) Layout.fillWidth: true onClicked: onClose() } PrimaryButton { - text: API.get().empty_string + (qsTr("View at Explorer")) + text: API.get().settings_pg.empty_string + (qsTr("View at Explorer")) Layout.fillWidth: true onClicked: General.viewTxAtExplorer(API.get().current_coin_info.ticker, tx_hash.text) } diff --git a/atomic_qt_design/qml/Wallet/Sidebar.qml b/atomic_qt_design/qml/Wallet/Sidebar.qml index d255753070..97aeb8eccf 100644 --- a/atomic_qt_design/qml/Wallet/Sidebar.qml +++ b/atomic_qt_design/qml/Wallet/Sidebar.qml @@ -162,7 +162,7 @@ Item { Menu { id: context_menu Action { - text: API.get().empty_string + (qsTr("Disable %1", "TICKER").arg(model.modelData.ticker)) + text: API.get().settings_pg.empty_string + (qsTr("Disable %1", "TICKER").arg(model.modelData.ticker)) onTriggered: API.get().disable_coins([model.modelData.ticker]) enabled: General.canDisable(model.modelData.ticker) } @@ -191,14 +191,14 @@ Item { // // Name // DefaultText { // Layout.alignment: Qt.AlignRight -// text_value: API.get().empty_string + (model.modelData.name.replace(" (TESTCOIN)", "")) +// text_value: API.get().settings_pg.empty_string + (model.modelData.name.replace(" (TESTCOIN)", "")) // font.pixelSize: text.length > 15 ? Style.textSizeVerySmall8 : text.length > 12 ? Style.textSizeVerySmall9 : Style.textSizeSmall1 // } // Ticker DefaultText { Layout.alignment: Qt.AlignRight - text_value: API.get().empty_string + (model.modelData.ticker) + text_value: API.get().settings_pg.empty_string + (model.modelData.ticker) font.pixelSize: text.length > 15 ? Style.textSizeVerySmall8 : text.length > 12 ? Style.textSizeVerySmall9 : Style.textSizeSmall1 // font.pixelSize: Style.textSizeSmall1 // color: Style.colorThemePassive @@ -208,7 +208,7 @@ Item { visible: mouse_area.containsMouse background: FloatingBackground { auto_set_size: false } contentItem: DefaultText { - text_value: API.get().empty_string + (model.modelData.name.replace(" (TESTCOIN)", "")) + text_value: API.get().settings_pg.empty_string + (model.modelData.name.replace(" (TESTCOIN)", "")) font.pixelSize: Style.textSizeSmall4 } } diff --git a/atomic_qt_design/qml/Wallet/TransactionDetailsModal.qml b/atomic_qt_design/qml/Wallet/TransactionDetailsModal.qml index fc308b2251..f46b441ea4 100644 --- a/atomic_qt_design/qml/Wallet/TransactionDetailsModal.qml +++ b/atomic_qt_design/qml/Wallet/TransactionDetailsModal.qml @@ -22,68 +22,68 @@ DefaultModal { width: 700 ModalHeader { - title: API.get().empty_string + (qsTr("Transaction Details")) + title: API.get().settings_pg.empty_string + (qsTr("Transaction Details")) } // Amount TextWithTitle { - title: API.get().empty_string + (qsTr("Amount")) - text: API.get().empty_string + (General.formatCrypto(details.received, details.amount, API.get().current_coin_info.ticker, details.amount_fiat, API.get().current_currency)) + title: API.get().settings_pg.empty_string + (qsTr("Amount")) + text: API.get().settings_pg.empty_string + (General.formatCrypto(details.received, details.amount, API.get().current_coin_info.ticker, details.amount_fiat, API.get().settings_pg.current_currency)) value_color: details.received ? Style.colorGreen : Style.colorRed privacy: true } // Fees TextWithTitle { - title: API.get().empty_string + (qsTr("Fees")) - text: API.get().empty_string + (General.formatCrypto("", details.fees, General.txFeeTicker(API.get().current_coin_info))) + title: API.get().settings_pg.empty_string + (qsTr("Fees")) + text: API.get().settings_pg.empty_string + (General.formatCrypto("", details.fees, General.txFeeTicker(API.get().current_coin_info))) privacy: true } // Date TextWithTitle { - title: API.get().empty_string + (qsTr("Date")) - text: API.get().empty_string + (details.timestamp === 0 ? qsTr("Unconfirmed"): details.date) + title: API.get().settings_pg.empty_string + (qsTr("Date")) + text: API.get().settings_pg.empty_string + (details.timestamp === 0 ? qsTr("Unconfirmed"): details.date) } // Transaction Hash TextWithTitle { - title: API.get().empty_string + (qsTr("Transaction Hash")) - text: API.get().empty_string + (details.tx_hash) + title: API.get().settings_pg.empty_string + (qsTr("Transaction Hash")) + text: API.get().settings_pg.empty_string + (details.tx_hash) privacy: true } // Confirmations TextWithTitle { - title: API.get().empty_string + (qsTr("Confirmations")) - text: API.get().empty_string + (details.confirmations) + title: API.get().settings_pg.empty_string + (qsTr("Confirmations")) + text: API.get().settings_pg.empty_string + (details.confirmations) } // Block Height TextWithTitle { - title: API.get().empty_string + (qsTr("Block Height")) - text: API.get().empty_string + (details.blockheight) + title: API.get().settings_pg.empty_string + (qsTr("Block Height")) + text: API.get().settings_pg.empty_string + (details.blockheight) } AddressList { - title: API.get().empty_string + (qsTr("From")) + title: API.get().settings_pg.empty_string + (qsTr("From")) model: details.from } AddressList { - title: API.get().empty_string + (qsTr("To")) + title: API.get().settings_pg.empty_string + (qsTr("To")) model: details.to } // Buttons RowLayout { DefaultButton { - text: API.get().empty_string + (qsTr("Close")) + text: API.get().settings_pg.empty_string + (qsTr("Close")) Layout.fillWidth: true onClicked: root.close() } PrimaryButton { - text: API.get().empty_string + (qsTr("View at Explorer")) + text: API.get().settings_pg.empty_string + (qsTr("View at Explorer")) Layout.fillWidth: true onClicked: General.viewTxAtExplorer(API.get().current_coin_info.ticker, details.tx_hash) } diff --git a/atomic_qt_design/qml/Wallet/Transactions.qml b/atomic_qt_design/qml/Wallet/Transactions.qml index b43a38e6fd..ed2bba3a45 100644 --- a/atomic_qt_design/qml/Wallet/Transactions.qml +++ b/atomic_qt_design/qml/Wallet/Transactions.qml @@ -48,7 +48,7 @@ DefaultListView { // Description DefaultText { id: description - text_value: API.get().empty_string + (model.modelData.received ? qsTr("Incoming transaction") : qsTr("Outgoing transaction")) + text_value: API.get().settings_pg.empty_string + (model.modelData.received ? qsTr("Incoming transaction") : qsTr("Outgoing transaction")) font.pixelSize: Style.textSizeSmall1 anchors.verticalCenter: parent.verticalCenter anchors.left: received_icon.right @@ -58,7 +58,7 @@ DefaultListView { // Crypto DefaultText { id: crypto_amount - text_value: API.get().empty_string + (General.formatCrypto(model.modelData.received, model.modelData.amount, API.get().current_coin_info.ticker)) + text_value: API.get().settings_pg.empty_string + (General.formatCrypto(model.modelData.received, model.modelData.amount, API.get().current_coin_info.ticker)) font.pixelSize: description.font.pixelSize anchors.verticalCenter: parent.verticalCenter anchors.left: parent.left @@ -69,7 +69,7 @@ DefaultListView { // Fiat DefaultText { - text_value: API.get().empty_string + (General.formatFiat(model.modelData.received, model.modelData.amount_fiat, API.get().current_currency)) + text_value: API.get().settings_pg.empty_string + (General.formatFiat(model.modelData.received, model.modelData.amount_fiat, API.get().settings_pg.current_currency)) font.pixelSize: description.font.pixelSize anchors.verticalCenter: parent.verticalCenter anchors.left: parent.left @@ -80,7 +80,7 @@ DefaultListView { // Fee DefaultText { - text_value: API.get().empty_string + (General.formatCrypto(!(parseFloat(model.modelData.fees) > 0), Math.abs(parseFloat(model.modelData.fees)), + text_value: API.get().settings_pg.empty_string + (General.formatCrypto(!(parseFloat(model.modelData.fees) > 0), Math.abs(parseFloat(model.modelData.fees)), General.txFeeTicker(API.get().current_coin_info)) + " " + qsTr("transaction fee")) font.pixelSize: description.font.pixelSize anchors.verticalCenter: parent.verticalCenter @@ -92,7 +92,7 @@ DefaultListView { // Date DefaultText { font.pixelSize: description.font.pixelSize - text_value: API.get().empty_string + (model.modelData.timestamp === 0 ? qsTr("Unconfirmed"): model.modelData.date) + text_value: API.get().settings_pg.empty_string + (model.modelData.timestamp === 0 ? qsTr("Unconfirmed"): model.modelData.date) anchors.verticalCenter: parent.verticalCenter anchors.right: parent.right anchors.rightMargin: 20 diff --git a/atomic_qt_design/qml/main.qml b/atomic_qt_design/qml/main.qml index 94d0e1be8d..2c1baf243a 100644 --- a/atomic_qt_design/qml/main.qml +++ b/atomic_qt_design/qml/main.qml @@ -10,7 +10,7 @@ Window { height: General.height minimumWidth: General.minimumWidth minimumHeight: General.minimumHeight - title: API.get().empty_string + (qsTr("AtomicDEX Pro")) + title: API.get().settings_pg.empty_string + (qsTr("AtomicDEX Pro")) flags: Qt.Window | Qt.WindowFullscreenButtonHint Component.onCompleted: showMaximized() diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index c3f0373a2b..0f0c8dfe71 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -42,6 +42,7 @@ #include "atomic.dex.provider.cex.prices.hpp" #include "atomic.dex.provider.coinpaprika.hpp" #include "atomic.dex.qt.bindings.hpp" +#include "atomic.dex.qt.settings.page.hpp" #include "atomic.dex.qt.utilities.hpp" #include "atomic.dex.security.hpp" #include "atomic.dex.update.service.hpp" @@ -198,7 +199,8 @@ namespace atomic_dex if (m_event_actions[events_action::need_a_full_refresh_of_mm2]) { auto& mm2_s = system_manager_.create_system(); - system_manager_.create_system(mm2_s, m_config); + + system_manager_.create_system(mm2_s, system_manager_.get_system().get_cfg()); system_manager_.create_system(mm2_s); system_manager_.create_system(system_manager_, m_event_actions.at(events_action::about_to_exit_app), get_portfolio(), this); @@ -218,7 +220,8 @@ namespace atomic_dex } std::error_code ec; - auto fiat_balance_std = paprika.get_price_in_fiat_all(m_config.current_currency, ec); + const auto& config = system_manager_.get_system().get_cfg(); + auto fiat_balance_std = paprika.get_price_in_fiat_all(config.current_currency, ec); if (!ec) { @@ -293,12 +296,13 @@ namespace atomic_dex QString target_balance = QString::fromStdString(mm2.my_balance(m_coin_info->get_ticker().toStdString(), ec)); m_coin_info->set_balance(target_balance); - if (std::any_of(begin(m_config.possible_currencies), end(m_config.possible_currencies), [this](const std::string& cur_fiat) { - return cur_fiat == m_config.current_currency; + const auto& config = system_manager_.get_system().get_cfg(); + if (std::any_of(begin(config.possible_currencies), end(config.possible_currencies), [&config](const std::string& cur_fiat) { + return cur_fiat == config.current_currency; })) { ec = std::error_code(); - auto amount = QString::fromStdString(paprika.get_price_in_fiat(m_config.current_currency, m_coin_info->get_ticker().toStdString(), ec)); + auto amount = QString::fromStdString(paprika.get_price_in_fiat(config.current_currency, m_coin_info->get_ticker().toStdString(), ec)); if (!ec) { m_coin_info->set_fiat_amount(amount); @@ -314,7 +318,8 @@ namespace atomic_dex auto txs = mm2.get_tx_history(ticker, ec); if (!ec) { - m_coin_info->set_transactions(to_qt_binding(std::move(txs), get_paprika(), m_config.current_currency, ticker)); + const auto& config = system_manager_.get_system().get_cfg(); + m_coin_info->set_transactions(to_qt_binding(std::move(txs), get_paprika(), config.current_currency, ticker)); } auto tx_state = mm2.get_tx_state(ticker, ec); @@ -376,7 +381,7 @@ namespace atomic_dex {"update_needed", false}, {"changelog", ""}, {"current_version", ""}, {"download_url", ""}, {"new_version", ""}, {"rpc_code", 0}, {"status", ""}}), m_coin_info(new current_coin_info(dispatcher_, this)), m_manager_models{ {"addressbook", new addressbook_model(this->m_wallet_manager, this)}, - {"portfolio", new portfolio_model(this->system_manager_, this->m_config, this)}, + {"portfolio", new portfolio_model(this->system_manager_, this->dispatcher_, this)}, {"orders", new orders_model(this->system_manager_, this->dispatcher_, this)}, {"internet_service", std::addressof(system_manager_.create_system(this))}, @@ -384,8 +389,10 @@ namespace atomic_dex { get_dispatcher().sink().connect<&application::on_refresh_update_status_event>(*this); //! MM2 system need to be created before the GUI and give the instance to the gui - auto& mm2_system = system_manager_.create_system(); - system_manager_.create_system(mm2_system, m_config); + auto& mm2_system = system_manager_.create_system(); + auto& settings_page_system = system_manager_.create_system(m_app, this); + get_portfolio()->set_cfg(settings_page_system.get_cfg()); + system_manager_.create_system(mm2_system, settings_page_system.get_cfg()); system_manager_.create_system(mm2_system); system_manager_.create_system(); system_manager_.create_system(system_manager_, m_event_actions.at(events_action::about_to_exit_app), get_portfolio(), this); @@ -425,55 +432,6 @@ namespace atomic_dex qobject_cast(m_manager_models.at("portfolio"))->initialize_portfolio(evt.ticker); } - QString - application::get_current_currency_sign() const noexcept - { - return QString::fromStdString(this->m_config.current_currency_sign); - } - - QString - application::get_current_fiat_sign() const noexcept - { - return QString::fromStdString(this->m_config.current_fiat_sign); - } - - QString - application::get_current_currency() const noexcept - { - return QString::fromStdString(this->m_config.current_currency); - } - - void - application::set_current_currency(const QString& current_currency) noexcept - { - if (current_currency.toStdString() != m_config.current_currency) - { - spdlog::info("change currency {} to {}", m_config.current_currency, current_currency.toStdString()); - atomic_dex::change_currency(m_config, current_currency.toStdString()); - qobject_cast(m_manager_models.at("portfolio"))->update_currency_values(); - emit onCurrencyChanged(); - emit onCurrencySignChanged(); - emit onFiatSignChanged(); - } - } - - QString - application::get_current_fiat() const noexcept - { - return QString::fromStdString(this->m_config.current_fiat); - } - - void - application::set_current_fiat(const QString& current_fiat) noexcept - { - if (current_fiat.toStdString() != m_config.current_fiat) - { - spdlog::info("change fiat {} to {}", m_config.current_fiat, current_fiat.toStdString()); - atomic_dex::change_fiat(m_config, current_fiat.toStdString()); - emit onFiatChanged(); - } - } - void application::on_change_ticker_event([[maybe_unused]] const change_ticker_event& evt) noexcept { @@ -830,7 +788,7 @@ namespace atomic_dex return out; } - QString + /*QString application::get_current_lang() const noexcept { return m_current_lang; @@ -868,49 +826,22 @@ namespace atomic_dex this->m_app->installTranslator(&m_translator); emit onLangChanged(); emit langChanged(); - } + }*/ void application::set_qt_app(std::shared_ptr app) noexcept { this->m_app = app; connect(m_app.get(), SIGNAL(aboutToQuit()), this, SLOT(exit_handler())); - set_current_lang(QString::fromStdString(m_config.current_lang)); - } - - QStringList - application::get_available_langs() const - { - QStringList out; - out.reserve(m_config.available_lang.size()); - for (auto&& cur_lang: m_config.available_lang) { out.push_back(QString::fromStdString(cur_lang)); } - return out; - } - - QStringList - application::get_available_fiats() const - { - QStringList out; - out.reserve(m_config.available_fiat.size()); - for (auto&& cur_fiat: m_config.available_fiat) { out.push_back(QString::fromStdString(cur_fiat)); } - return out; + system_manager_.get_system().init_lang(); } - QStringList - application::get_available_currencies() const - { - QStringList out; - out.reserve(m_config.possible_currencies.size()); - for (auto&& cur_currency: m_config.possible_currencies) { out.push_back(QString::fromStdString(cur_currency)); } - return out; - } - - const QString& + /*const QString& application::get_empty_string() { static const QString empty_string = ""; return empty_string; - } + }*/ QString application::retrieve_seed(const QString& wallet_name, const QString& password) @@ -1110,7 +1041,8 @@ namespace atomic_dex application::get_fiat_from_amount(const QString& ticker, const QString& amount) { std::error_code ec; - return QString::fromStdString(get_paprika().get_price_as_currency_from_amount(m_config.current_fiat, ticker.toStdString(), amount.toStdString(), ec)); + const auto& config = system_manager_.get_system().get_cfg(); + return QString::fromStdString(get_paprika().get_price_as_currency_from_amount(config.current_fiat, ticker.toStdString(), amount.toStdString(), ec)); } } // namespace atomic_dex @@ -1296,8 +1228,9 @@ namespace atomic_dex m_coin_info->set_minimal_balance_for_asking_rewards(QString::fromStdString(info.minimal_claim_amount)); m_coin_info->set_explorer_url(QString::fromStdString(info.explorer_url[0])); std::error_code ec; - m_coin_info->set_price(QString::fromStdString(paprika.get_rate_conversion(m_config.current_currency, ticker, ec, true))); - m_coin_info->set_change24h(retrieve_change_24h(paprika, info, m_config)); + const auto& config = system_manager_.get_system().get_cfg(); + m_coin_info->set_price(QString::fromStdString(paprika.get_rate_conversion(config.current_currency, ticker, ec, true))); + m_coin_info->set_change24h(retrieve_change_24h(paprika, info, config)); m_coin_info->set_trend_7d(nlohmann_json_array_to_qt_json_array(paprika.get_ticker_historical(ticker).answer)); } } @@ -1323,6 +1256,18 @@ namespace atomic_dex } } // namespace atomic_dex +//! Settings +namespace atomic_dex +{ + settings_page* + application::get_settings_page() const noexcept + { + settings_page* ptr = const_cast(std::addressof(system_manager_.get_system())); + assert(ptr != nullptr); + return ptr; + } +} + //! Notification namespace atomic_dex { diff --git a/src/atomic.dex.app.hpp b/src/atomic.dex.app.hpp index 8e4137f276..9450e5be9d 100644 --- a/src/atomic.dex.app.hpp +++ b/src/atomic.dex.app.hpp @@ -43,6 +43,7 @@ #include "atomic.dex.qt.orderbook.hpp" #include "atomic.dex.qt.orders.model.hpp" #include "atomic.dex.qt.portfolio.model.hpp" +#include "atomic.dex.qt.settings.page.hpp" #include "atomic.dex.qt.trading.page.hpp" #include "atomic.dex.qt.wallet.manager.hpp" @@ -55,7 +56,6 @@ namespace atomic_dex Q_OBJECT //! Properties - Q_PROPERTY(QString empty_string READ get_empty_string NOTIFY langChanged) Q_PROPERTY(QList enabled_coins READ get_enabled_coins NOTIFY enabledCoinsChanged) Q_PROPERTY(QList enableable_coins READ get_enableable_coins NOTIFY enableableCoinsChanged) Q_PROPERTY(QObject* current_coin_info READ get_current_coin_info NOTIFY coinInfoChanged) @@ -66,11 +66,8 @@ namespace atomic_dex Q_PROPERTY(notification_manager* notification_mgr READ get_notification_manager) Q_PROPERTY(internet_service_checker* internet_checker READ get_internet_checker NOTIFY internetCheckerChanged) Q_PROPERTY(trading_page* trading_pg READ get_trading_page NOTIFY tradingPageChanged) - Q_PROPERTY(QString current_currency READ get_current_currency WRITE set_current_currency NOTIFY onCurrencyChanged) - Q_PROPERTY(QString current_currency_sign READ get_current_currency_sign NOTIFY onCurrencySignChanged) - Q_PROPERTY(QString current_fiat_sign READ get_current_fiat_sign NOTIFY onFiatSignChanged) - Q_PROPERTY(QString current_fiat READ get_current_fiat WRITE set_current_fiat NOTIFY onFiatChanged) - Q_PROPERTY(QString lang READ get_current_lang WRITE set_current_lang NOTIFY onLangChanged) + Q_PROPERTY(settings_page* settings_pg READ get_settings_page NOTIFY settingsPageChanged) + // Q_PROPERTY(QString lang READ get_current_lang WRITE set_current_lang NOTIFY onLangChanged) Q_PROPERTY(QString wallet_default_name READ get_wallet_default_name WRITE set_wallet_default_name NOTIFY onWalletDefaultNameChanged) Q_PROPERTY(QString balance_fiat_all READ get_balance_fiat_all WRITE set_current_balance_fiat_all NOTIFY onFiatBalanceAllChanged) Q_PROPERTY(QString initial_loading_status READ get_status WRITE set_status NOTIFY onStatusChanged) @@ -100,7 +97,7 @@ namespace atomic_dex using t_events_actions = std::array; //! Private members fields - atomic_dex::cfg m_config{load_cfg()}; + // atomic_dex::cfg m_config{load_cfg()}; std::shared_ptr m_app; atomic_dex::qt_wallet_manager m_wallet_manager; t_actions_queue m_actions_queue{g_max_actions_size}; @@ -108,13 +105,13 @@ namespace atomic_dex QVariantList m_enabled_coins; QVariantList m_enableable_coins; QVariant m_update_status; - QTranslator m_translator; - QString m_current_lang{QString::fromStdString(m_config.current_lang)}; - QString m_current_status{"None"}; - QString m_current_balance_all{"0.00"}; - current_coin_info* m_coin_info; - t_manager_model_registry m_manager_models; - t_events_actions m_event_actions{{false}}; + // QTranslator m_translator; + // QString m_current_lang{QString::fromStdString(m_config.current_lang)}; + QString m_current_status{"None"}; + QString m_current_balance_all{"0.00"}; + current_coin_info* m_coin_info; + t_manager_model_registry m_manager_models; + t_events_actions m_event_actions{{false}}; public: //! Constructor @@ -136,25 +133,26 @@ namespace atomic_dex void on_process_swaps_finished_event(const process_swaps_finished&) noexcept; //! Properties Getter - static const QString& get_empty_string(); - mm2& get_mm2() noexcept; - const mm2& get_mm2() const noexcept; - coinpaprika_provider& get_paprika() noexcept; - entt::dispatcher& get_dispatcher() noexcept; - QObject* get_current_coin_info() const noexcept; - addressbook_model* get_addressbook() const noexcept; - portfolio_model* get_portfolio() const noexcept; - orders_model* get_orders() const noexcept; - notification_manager* get_notification_manager() const noexcept; - trading_page* get_trading_page() const noexcept; - internet_service_checker* get_internet_checker() const noexcept; - QVariantList get_enabled_coins() const noexcept; - QVariantList get_enableable_coins() const noexcept; - QString get_current_currency() const noexcept; - QString get_current_currency_sign() const noexcept; - QString get_current_fiat_sign() const noexcept; - QString get_current_fiat() const noexcept; - QString get_current_lang() const noexcept; + // static const QString& get_empty_string(); + mm2& get_mm2() noexcept; + const mm2& get_mm2() const noexcept; + coinpaprika_provider& get_paprika() noexcept; + entt::dispatcher& get_dispatcher() noexcept; + QObject* get_current_coin_info() const noexcept; + addressbook_model* get_addressbook() const noexcept; + portfolio_model* get_portfolio() const noexcept; + orders_model* get_orders() const noexcept; + notification_manager* get_notification_manager() const noexcept; + trading_page* get_trading_page() const noexcept; + settings_page* get_settings_page() const noexcept;; + internet_service_checker* get_internet_checker() const noexcept; + QVariantList get_enabled_coins() const noexcept; + QVariantList get_enableable_coins() const noexcept; + // QString get_current_currency() const noexcept; + // QString get_current_currency_sign() const noexcept; + // QString get_current_fiat_sign() const noexcept; + // QString get_current_fiat() const noexcept; + // QString get_current_lang() const noexcept; QString get_balance_fiat_all() const noexcept; QString get_wallet_default_name() const noexcept; QString get_status() const noexcept; @@ -162,9 +160,9 @@ namespace atomic_dex Q_INVOKABLE static QString get_version() noexcept; //! Properties Setter - void set_current_currency(const QString& current_currency) noexcept; - void set_current_fiat(const QString& current_fiat) noexcept; - void set_current_lang(const QString& current_lang) noexcept; + // void set_current_currency(const QString& current_currency) noexcept; + // void set_current_fiat(const QString& current_fiat) noexcept; + // void set_current_lang(const QString& current_lang) noexcept; void set_wallet_default_name(QString wallet_default_name) noexcept; void set_current_balance_fiat_all(QString current_fiat_all_balance) noexcept; void set_status(QString status) noexcept; @@ -190,9 +188,6 @@ namespace atomic_dex Q_INVOKABLE static QString get_mm2_version(); Q_INVOKABLE static QString get_log_folder(); Q_INVOKABLE static QString get_export_folder(); - Q_INVOKABLE QStringList get_available_langs() const; - Q_INVOKABLE QStringList get_available_fiats() const; - Q_INVOKABLE QStringList get_available_currencies() const; Q_INVOKABLE static void change_state(int visibility); //! Portfolio QML API Bindings @@ -215,9 +210,9 @@ namespace atomic_dex Q_INVOKABLE bool enable_coins(const QStringList& coins); Q_INVOKABLE QString get_balance(const QString& coin); Q_INVOKABLE static QString get_price_amount(const QString& base_amount, const QString& rel_amount); - Q_INVOKABLE bool do_i_have_enough_funds(const QString& ticker, const QString& amount) const; - Q_INVOKABLE bool disable_coins(const QStringList& coins); - Q_INVOKABLE bool is_claiming_ready(const QString& ticker); + Q_INVOKABLE bool do_i_have_enough_funds(const QString& ticker, const QString& amount) const; + Q_INVOKABLE bool disable_coins(const QStringList& coins); + Q_INVOKABLE bool is_claiming_ready(const QString& ticker); Q_INVOKABLE QObject* claim_rewards(const QString& ticker); @@ -235,14 +230,14 @@ namespace atomic_dex void enabledCoinsChanged(); void enableableCoinsChanged(); void coinInfoChanged(); - void onCurrencyChanged(); - void onCurrencySignChanged(); - void onFiatSignChanged(); - void onFiatChanged(); - void onLangChanged(); - void langChanged(); + // void onCurrencyChanged(); + // void onCurrencySignChanged(); + // void onFiatSignChanged(); + // void onFiatChanged(); + // void onLangChanged(); + // void langChanged(); void onFiatBalanceAllChanged(); - void onSecondFiatBalanceAllChanged(); + // void onSecondFiatBalanceAllChanged(); void onStatusChanged(); void onWalletDefaultNameChanged(); void myOrdersUpdated(); @@ -251,6 +246,7 @@ namespace atomic_dex void updateStatusChanged(); void ordersChanged(); void tradingPageChanged(); + void settingsPageChanged(); void internetCheckerChanged(); public slots: void exit_handler(); diff --git a/src/atomic.dex.cfg.cpp b/src/atomic.dex.cfg.cpp index 56ca15282a..49cae251ef 100644 --- a/src/atomic.dex.cfg.cpp +++ b/src/atomic.dex.cfg.cpp @@ -63,8 +63,11 @@ namespace atomic_dex void change_lang(cfg& config, const std::string& new_lang) { - config.current_lang = new_lang; - upgrade_cfg(config); + if (config.current_lang != new_lang) + { + config.current_lang = new_lang; + upgrade_cfg(config); + } } cfg diff --git a/src/atomic.dex.events.hpp b/src/atomic.dex.events.hpp index 6767099c71..ade6fae801 100644 --- a/src/atomic.dex.events.hpp +++ b/src/atomic.dex.events.hpp @@ -32,6 +32,7 @@ namespace atomic_dex using refresh_update_status = entt::tag<"gui_refresh_update_status"_hs>; using process_orders_finished = entt::tag<"gui_process_orders_finished"_hs>; using process_swaps_finished = entt::tag<"gui_process_swaps_finished"_hs>; + using update_portfolio_values = entt::tag<"update_portfolio_values"_hs>; // using process_orderbook_finished = entt::tag<"gui_process_orderbook_finished"_hs>; struct process_orderbook_finished diff --git a/src/atomic.dex.qt.portfolio.model.cpp b/src/atomic.dex.qt.portfolio.model.cpp index 729a87ad11..3e61d1a0c2 100644 --- a/src/atomic.dex.qt.portfolio.model.cpp +++ b/src/atomic.dex.qt.portfolio.model.cpp @@ -34,12 +34,13 @@ namespace namespace atomic_dex { - portfolio_model::portfolio_model(ag::ecs::system_manager& system_manager, atomic_dex::cfg& config, QObject* parent) noexcept : - QAbstractListModel(parent), m_system_manager(system_manager), m_config(config), m_model_proxy(new portfolio_proxy_model(this)) + portfolio_model::portfolio_model(ag::ecs::system_manager& system_manager, entt::dispatcher& dispatcher, QObject* parent) noexcept : + QAbstractListModel(parent), m_system_manager(system_manager), m_model_proxy(new portfolio_proxy_model(this)) { spdlog::trace("{} l{} f[{}]", __FUNCTION__, __LINE__, fs::path(__FILE__).filename().string()); spdlog::trace("portfolio model created"); + dispatcher.sink().connect<&portfolio_model::on_update_portfolio_values_event>(*this); this->m_model_proxy->setSourceModel(this); this->m_model_proxy->setDynamicSortFilter(true); this->m_model_proxy->sort_by_currency_balance(false); @@ -62,14 +63,14 @@ namespace atomic_dex beginInsertRows(QModelIndex(), this->m_model_data.count(), this->m_model_data.count()); std::error_code ec; - const QString change_24h = retrieve_change_24h(paprika, coin, m_config); + const QString change_24h = retrieve_change_24h(paprika, coin, *m_config); portfolio_data data{ .ticker = QString::fromStdString(coin.ticker), .name = QString::fromStdString(coin.name), .balance = QString::fromStdString(mm2_system.my_balance(coin.ticker, ec)), - .main_currency_balance = QString::fromStdString(paprika.get_price_in_fiat(m_config.current_currency, coin.ticker, ec)), + .main_currency_balance = QString::fromStdString(paprika.get_price_in_fiat(m_config->current_currency, coin.ticker, ec)), .change_24h = change_24h, - .main_currency_price_for_one_unit = QString::fromStdString(paprika.get_rate_conversion(m_config.current_currency, coin.ticker, ec, true)), + .main_currency_price_for_one_unit = QString::fromStdString(paprika.get_rate_conversion(m_config->current_currency, coin.ticker, ec, true)), .trend_7d = nlohmann_json_array_to_qt_json_array(paprika.get_ticker_historical(coin.ticker).answer), .is_excluded = false, }; @@ -88,7 +89,7 @@ namespace atomic_dex const auto& mm2_system = this->m_system_manager.get_system(); const auto& paprika = this->m_system_manager.get_system(); t_coins coins = mm2_system.get_enabled_coins(); - const std::string& currency = m_config.current_currency; + const std::string& currency = m_config->current_currency; std::vector> pending_tasks; for (auto&& coin: coins) { @@ -102,7 +103,7 @@ namespace atomic_dex update_value(MainCurrencyBalanceRole, main_currency_balance_value, idx, *this); const QString currency_price_for_one_unit = QString::fromStdString(paprika.get_rate_conversion(currency, ticker, ec, true)); update_value(MainCurrencyPriceForOneUnit, currency_price_for_one_unit, idx, *this); - QString change24_h = retrieve_change_24h(paprika, coin, m_config); + QString change24_h = retrieve_change_24h(paprika, coin, *m_config); update_value(Change24H, change24_h, idx, *this); const QString balance = QString::fromStdString(mm2_system.my_balance(coin.ticker, ec)); update_value(BalanceRole, balance, idx, *this); @@ -122,7 +123,7 @@ namespace atomic_dex const auto& mm2_system = this->m_system_manager.get_system(); const auto& paprika = this->m_system_manager.get_system(); std::error_code ec; - const std::string& currency = m_config.current_currency; + const std::string& currency = m_config->current_currency; const QModelIndex& idx = res.at(0); const QString balance = QString::fromStdString(mm2_system.my_balance(ticker, ec)); update_value(BalanceRole, balance, idx, *this); @@ -262,4 +263,15 @@ namespace atomic_dex { return this->rowCount(QModelIndex()); } + + void + portfolio_model::set_cfg(cfg& cfg) noexcept + { + m_config = &cfg; + } + void + portfolio_model::on_update_portfolio_values_event(const update_portfolio_values&) noexcept + { + this->update_currency_values(); + } } // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.portfolio.model.hpp b/src/atomic.dex.qt.portfolio.model.hpp index 6b89ef60c4..aad4645e03 100644 --- a/src/atomic.dex.qt.portfolio.model.hpp +++ b/src/atomic.dex.qt.portfolio.model.hpp @@ -29,6 +29,7 @@ #include "atomic.dex.provider.coinpaprika.hpp" #include "atomic.dex.qt.portfolio.data.hpp" #include "atomic.dex.qt.portfolio.proxy.filter.model.hpp" +#include "atomic.dex.events.hpp" namespace atomic_dex { @@ -58,9 +59,12 @@ namespace atomic_dex public: //! Constructor / Destructor - explicit portfolio_model(ag::ecs::system_manager& system_manager, atomic_dex::cfg& config, QObject* parent = nullptr) noexcept; + explicit portfolio_model(ag::ecs::system_manager& system_manager, entt::dispatcher& dispatcher, QObject* parent = nullptr) noexcept; ~portfolio_model() noexcept final; + //! Public callback + void on_update_portfolio_values_event(const update_portfolio_values&) noexcept; + //! Overrides [[nodiscard]] QVariant data(const QModelIndex& index, int role) const final; bool setData(const QModelIndex& index, const QVariant& value, int role) final; //< Will be used internally @@ -73,10 +77,11 @@ namespace atomic_dex void update_currency_values(); void update_balance_values(const std::string& ticker) noexcept; void disable_coins(const QStringList& coins); + void set_cfg(atomic_dex::cfg& cfg) noexcept; //! Properties [[nodiscard]] portfolio_proxy_model* get_portfolio_proxy_mdl() const noexcept; - [[nodiscard]] int get_length() const noexcept; + [[nodiscard]] int get_length() const noexcept; signals: void portfolioProxyChanged(); @@ -85,7 +90,7 @@ namespace atomic_dex private: //! From project ag::ecs::system_manager& m_system_manager; - atomic_dex::cfg& m_config; + atomic_dex::cfg* m_config; //! Properties portfolio_proxy_model* m_model_proxy; diff --git a/src/atomic.dex.qt.settings.page.cpp b/src/atomic.dex.qt.settings.page.cpp index 92773d57c2..589fd0bacc 100644 --- a/src/atomic.dex.qt.settings.page.cpp +++ b/src/atomic.dex.qt.settings.page.cpp @@ -14,12 +14,18 @@ * * ******************************************************************************/ +//! QT +#include +#include + +//! Project Headers #include "atomic.dex.qt.settings.page.hpp" +#include "atomic.dex.events.hpp" //! Constructo destructor namespace atomic_dex { - settings_page::settings_page(entt::registry& registry, QObject* parent) noexcept : QObject(parent), system(registry) {} + settings_page::settings_page(entt::registry& registry, std::shared_ptr app, QObject* parent) noexcept : QObject(parent), system(registry), m_app(app) {} } // namespace atomic_dex //! Override @@ -29,4 +35,151 @@ namespace atomic_dex settings_page::update() noexcept { } -} // namespace atomic_dex \ No newline at end of file +} // namespace atomic_dex + +//! Properties +namespace atomic_dex +{ + QString settings_page::get_empty_string() const noexcept + { + return m_empty_string; + } + + QString + settings_page::get_current_lang() const noexcept + { + return QString::fromStdString(m_config.current_lang); + } + + void + atomic_dex::settings_page::set_current_lang(QString new_lang) noexcept + { + const std::string new_lang_std = new_lang.toStdString(); + change_lang(m_config, new_lang_std); + + auto get_locale = [](const std::string& current_lang) { + if (current_lang == "tr") + { + return QLocale::Language::Turkish; + } + if (current_lang == "en") + { + return QLocale::Language::English; + } + if (current_lang == "fr") + { + return QLocale::Language::French; + } + return QLocale::Language::AnyLanguage; + }; + + qDebug() << "locale before: " << QLocale().name(); + QLocale::setDefault(get_locale(m_config.current_lang)); + qDebug() << "locale after: " << QLocale().name(); + [[maybe_unused]] auto res = this->m_translator.load("atomic_qt_" + new_lang, QLatin1String(":/atomic_qt_design/assets/languages")); + assert(res); + this->m_app->installTranslator(&m_translator); + emit onLangChanged(); + emit langChanged(); + } + + QString + settings_page::get_current_currency_sign() const noexcept + { + return QString::fromStdString(this->m_config.current_currency_sign); + } + + QString + settings_page::get_current_fiat_sign() const noexcept + { + return QString::fromStdString(this->m_config.current_fiat_sign); + } + + QString + settings_page::get_current_currency() const noexcept + { + return QString::fromStdString(this->m_config.current_currency); + } + + void + settings_page::set_current_currency(const QString& current_currency) noexcept + { + if (current_currency.toStdString() != m_config.current_currency) + { + spdlog::info("change currency {} to {}", m_config.current_currency, current_currency.toStdString()); + atomic_dex::change_currency(m_config, current_currency.toStdString()); + this->dispatcher_.trigger(); + emit onCurrencyChanged(); + emit onCurrencySignChanged(); + emit onFiatSignChanged(); + } + } + + QString + settings_page::get_current_fiat() const noexcept + { + return QString::fromStdString(this->m_config.current_fiat); + } + + void + settings_page::set_current_fiat(const QString& current_fiat) noexcept + { + if (current_fiat.toStdString() != m_config.current_fiat) + { + spdlog::info("change fiat {} to {}", m_config.current_fiat, current_fiat.toStdString()); + atomic_dex::change_fiat(m_config, current_fiat.toStdString()); + emit onFiatChanged(); + } + } +} // namespace atomic_dex + +//! Public API +namespace atomic_dex +{ + atomic_dex::cfg& settings_page::get_cfg() noexcept + { + return m_config; + } + + const atomic_dex::cfg& settings_page::get_cfg() const noexcept + { + return m_config; + + } + + void settings_page::init_lang() noexcept + { + set_current_lang(QString::fromStdString(m_config.current_lang)); + } +} + +//! QML API +namespace atomic_dex +{ + QStringList + settings_page::get_available_langs() const + { + QStringList out; + out.reserve(m_config.available_lang.size()); + for (auto&& cur_lang: m_config.available_lang) { out.push_back(QString::fromStdString(cur_lang)); } + return out; + } + + QStringList + settings_page::get_available_fiats() const + { + QStringList out; + out.reserve(m_config.available_fiat.size()); + for (auto&& cur_fiat: m_config.available_fiat) { out.push_back(QString::fromStdString(cur_fiat)); } + return out; + } + + QStringList + settings_page::get_available_currencies() const + { + QStringList out; + out.reserve(m_config.possible_currencies.size()); + for (auto&& cur_currency: m_config.possible_currencies) { out.push_back(QString::fromStdString(cur_currency)); } + return out; + } +} \ No newline at end of file diff --git a/src/atomic.dex.qt.settings.page.hpp b/src/atomic.dex.qt.settings.page.hpp index 360335ff26..0d376339c0 100644 --- a/src/atomic.dex.qt.settings.page.hpp +++ b/src/atomic.dex.qt.settings.page.hpp @@ -17,11 +17,17 @@ #pragma once //! QT +#include #include +#include +#include //! PCH #include "atomic.dex.pch.hpp" +//! Project headers +#include "atomic.dex.cfg.hpp" + namespace atomic_dex { class settings_page final : public QObject, public ag::ecs::pre_update_system @@ -29,12 +35,55 @@ namespace atomic_dex //! Q_Object definition Q_OBJECT + //! Properties + Q_PROPERTY(QString lang READ get_current_lang WRITE set_current_lang NOTIFY onLangChanged) + Q_PROPERTY(QString empty_string READ get_empty_string NOTIFY langChanged) + Q_PROPERTY(QString current_currency READ get_current_currency WRITE set_current_currency NOTIFY onCurrencyChanged) + Q_PROPERTY(QString current_currency_sign READ get_current_currency_sign NOTIFY onCurrencySignChanged) + Q_PROPERTY(QString current_fiat_sign READ get_current_fiat_sign NOTIFY onFiatSignChanged) + Q_PROPERTY(QString current_fiat READ get_current_fiat WRITE set_current_fiat NOTIFY onFiatChanged) + + //! Private member fields Fields + std::shared_ptr m_app; + atomic_dex::cfg m_config{load_cfg()}; + QTranslator m_translator; + QString m_empty_string{""}; + public: - explicit settings_page(entt::registry& registry, QObject* parent = nullptr) noexcept; + explicit settings_page(entt::registry& registry, std::shared_ptr app, QObject* parent = nullptr) noexcept; ~settings_page() noexcept final = default; //! Public override void update() noexcept final; + + //! Properties + [[nodiscard]] QString get_current_lang() const noexcept; + void set_current_lang(QString new_lang) noexcept; + [[nodiscard]] QString get_empty_string() const noexcept; + [[nodiscard]] QString get_current_currency() const noexcept; + [[nodiscard]] QString get_current_currency_sign() const noexcept; + [[nodiscard]] QString get_current_fiat_sign() const noexcept; + [[nodiscard]] QString get_current_fiat() const noexcept; + void set_current_currency(const QString& current_currency) noexcept; + void set_current_fiat(const QString& current_fiat) noexcept; + + //! Public API + [[nodiscard]] atomic_dex::cfg& get_cfg() noexcept; + [[nodiscard]] const atomic_dex::cfg& get_cfg() const noexcept; + void init_lang() noexcept; + + //! Public QML API + Q_INVOKABLE QStringList get_available_langs() const; + Q_INVOKABLE QStringList get_available_fiats() const; + Q_INVOKABLE QStringList get_available_currencies() const; + + signals: + void onLangChanged(); + void langChanged(); + void onCurrencyChanged(); + void onCurrencySignChanged(); + void onFiatSignChanged(); + void onFiatChanged(); }; } // namespace atomic_dex From 51746079ad3c35afe3fabb0a2bae03eed2ac2ad5 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Sun, 9 Aug 2020 19:25:51 +0200 Subject: [PATCH 244/515] feat(settings): remove commentary --- src/atomic.dex.app.cpp | 47 ------------------------------------------ src/atomic.dex.app.hpp | 43 +++++++++++++------------------------- 2 files changed, 14 insertions(+), 76 deletions(-) diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index 0f0c8dfe71..20714fbc39 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -788,46 +788,6 @@ namespace atomic_dex return out; } - /*QString - application::get_current_lang() const noexcept - { - return m_current_lang; - } - - void - application::set_current_lang(const QString& current_lang) noexcept - { - this->m_current_lang = current_lang; - if (m_config.current_lang != current_lang.toStdString()) - { - change_lang(m_config, current_lang.toStdString()); - } - auto get_locale = [](const QString& current_lang) { - if (current_lang == "tr") - { - return QLocale::Language::Turkish; - } - if (current_lang == "en") - { - return QLocale::Language::English; - } - if (current_lang == "fr") - { - return QLocale::Language::French; - } - return QLocale::Language::AnyLanguage; - }; - - qDebug() << "locale before: " << QLocale().name(); - QLocale::setDefault(get_locale(current_lang)); - qDebug() << "locale after: " << QLocale().name(); - [[maybe_unused]] auto res = this->m_translator.load("atomic_qt_" + current_lang, QLatin1String(":/atomic_qt_design/assets/languages")); - assert(res); - this->m_app->installTranslator(&m_translator); - emit onLangChanged(); - emit langChanged(); - }*/ - void application::set_qt_app(std::shared_ptr app) noexcept { @@ -836,13 +796,6 @@ namespace atomic_dex system_manager_.get_system().init_lang(); } - /*const QString& - application::get_empty_string() - { - static const QString empty_string = ""; - return empty_string; - }*/ - QString application::retrieve_seed(const QString& wallet_name, const QString& password) { diff --git a/src/atomic.dex.app.hpp b/src/atomic.dex.app.hpp index 9450e5be9d..9b5271a939 100644 --- a/src/atomic.dex.app.hpp +++ b/src/atomic.dex.app.hpp @@ -134,25 +134,20 @@ namespace atomic_dex //! Properties Getter // static const QString& get_empty_string(); - mm2& get_mm2() noexcept; - const mm2& get_mm2() const noexcept; - coinpaprika_provider& get_paprika() noexcept; - entt::dispatcher& get_dispatcher() noexcept; - QObject* get_current_coin_info() const noexcept; - addressbook_model* get_addressbook() const noexcept; - portfolio_model* get_portfolio() const noexcept; - orders_model* get_orders() const noexcept; - notification_manager* get_notification_manager() const noexcept; - trading_page* get_trading_page() const noexcept; - settings_page* get_settings_page() const noexcept;; - internet_service_checker* get_internet_checker() const noexcept; - QVariantList get_enabled_coins() const noexcept; - QVariantList get_enableable_coins() const noexcept; - // QString get_current_currency() const noexcept; - // QString get_current_currency_sign() const noexcept; - // QString get_current_fiat_sign() const noexcept; - // QString get_current_fiat() const noexcept; - // QString get_current_lang() const noexcept; + mm2& get_mm2() noexcept; + const mm2& get_mm2() const noexcept; + coinpaprika_provider& get_paprika() noexcept; + entt::dispatcher& get_dispatcher() noexcept; + QObject* get_current_coin_info() const noexcept; + addressbook_model* get_addressbook() const noexcept; + portfolio_model* get_portfolio() const noexcept; + orders_model* get_orders() const noexcept; + notification_manager* get_notification_manager() const noexcept; + trading_page* get_trading_page() const noexcept; + settings_page* get_settings_page() const noexcept; + internet_service_checker* get_internet_checker() const noexcept; + QVariantList get_enabled_coins() const noexcept; + QVariantList get_enableable_coins() const noexcept; QString get_balance_fiat_all() const noexcept; QString get_wallet_default_name() const noexcept; QString get_status() const noexcept; @@ -160,9 +155,6 @@ namespace atomic_dex Q_INVOKABLE static QString get_version() noexcept; //! Properties Setter - // void set_current_currency(const QString& current_currency) noexcept; - // void set_current_fiat(const QString& current_fiat) noexcept; - // void set_current_lang(const QString& current_lang) noexcept; void set_wallet_default_name(QString wallet_default_name) noexcept; void set_current_balance_fiat_all(QString current_fiat_all_balance) noexcept; void set_status(QString status) noexcept; @@ -230,14 +222,7 @@ namespace atomic_dex void enabledCoinsChanged(); void enableableCoinsChanged(); void coinInfoChanged(); - // void onCurrencyChanged(); - // void onCurrencySignChanged(); - // void onFiatSignChanged(); - // void onFiatChanged(); - // void onLangChanged(); - // void langChanged(); void onFiatBalanceAllChanged(); - // void onSecondFiatBalanceAllChanged(); void onStatusChanged(); void onWalletDefaultNameChanged(); void myOrdersUpdated(); From 6d36403f9553ddf06e05a57b59e33689d3c48a09 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Sun, 9 Aug 2020 19:27:55 +0200 Subject: [PATCH 245/515] feat(settings): remove commentary --- src/atomic.dex.app.hpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/atomic.dex.app.hpp b/src/atomic.dex.app.hpp index 9b5271a939..c04064d25c 100644 --- a/src/atomic.dex.app.hpp +++ b/src/atomic.dex.app.hpp @@ -67,7 +67,6 @@ namespace atomic_dex Q_PROPERTY(internet_service_checker* internet_checker READ get_internet_checker NOTIFY internetCheckerChanged) Q_PROPERTY(trading_page* trading_pg READ get_trading_page NOTIFY tradingPageChanged) Q_PROPERTY(settings_page* settings_pg READ get_settings_page NOTIFY settingsPageChanged) - // Q_PROPERTY(QString lang READ get_current_lang WRITE set_current_lang NOTIFY onLangChanged) Q_PROPERTY(QString wallet_default_name READ get_wallet_default_name WRITE set_wallet_default_name NOTIFY onWalletDefaultNameChanged) Q_PROPERTY(QString balance_fiat_all READ get_balance_fiat_all WRITE set_current_balance_fiat_all NOTIFY onFiatBalanceAllChanged) Q_PROPERTY(QString initial_loading_status READ get_status WRITE set_status NOTIFY onStatusChanged) @@ -97,7 +96,6 @@ namespace atomic_dex using t_events_actions = std::array; //! Private members fields - // atomic_dex::cfg m_config{load_cfg()}; std::shared_ptr m_app; atomic_dex::qt_wallet_manager m_wallet_manager; t_actions_queue m_actions_queue{g_max_actions_size}; @@ -105,13 +103,11 @@ namespace atomic_dex QVariantList m_enabled_coins; QVariantList m_enableable_coins; QVariant m_update_status; - // QTranslator m_translator; - // QString m_current_lang{QString::fromStdString(m_config.current_lang)}; - QString m_current_status{"None"}; - QString m_current_balance_all{"0.00"}; - current_coin_info* m_coin_info; - t_manager_model_registry m_manager_models; - t_events_actions m_event_actions{{false}}; + QString m_current_status{"None"}; + QString m_current_balance_all{"0.00"}; + current_coin_info* m_coin_info; + t_manager_model_registry m_manager_models; + t_events_actions m_event_actions{{false}}; public: //! Constructor From c9cb57a62d46cf0035a42d1f2d259cb331a89594 Mon Sep 17 00:00:00 2001 From: naezith Date: Sun, 9 Aug 2020 21:56:13 +0300 Subject: [PATCH 246/515] feat(gui): added read more about dpow text --- atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml index 2b197a8e34..171b4301af 100644 --- a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml +++ b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml @@ -118,7 +118,7 @@ DefaultModal { DefaultText { visible: config_section.is_dpow_configurable Layout.alignment: Qt.AlignHCenter - text_value: API.get().empty_string + (General.cex_icon + " " + qsTr('Read more about dPoW')) + text_value: API.get().settings_pg.empty_string + (General.cex_icon + " " + qsTr('Read more about dPoW')) wrapMode: Text.WordWrap font.pixelSize: Style.textSizeSmall2 From 2d701f0a6f3ee824a3adaec4e898243dfcbadebb Mon Sep 17 00:00:00 2001 From: naezith Date: Sun, 9 Aug 2020 22:05:40 +0300 Subject: [PATCH 247/515] feat(gui): add ticker to config label --- atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml index 171b4301af..214f2f5683 100644 --- a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml +++ b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml @@ -112,7 +112,7 @@ DefaultModal { Layout.alignment: Qt.AlignHCenter text_value: API.get().settings_pg.empty_string + ("✅ " + (config_section.is_dpow_configurable ? qsTr("dPoW protected") : - qsTr("%1 confirmations for incoming transactions").arg(config_section.default_config.required_confirmations))) + qsTr("%1 confirmations for incoming %2 transactions").arg(config_section.default_config.required_confirmations).arg(rel_ticker))) } DefaultText { From 20c421e263cedb6172a0c04830760cc2a83be452 Mon Sep 17 00:00:00 2001 From: naezith Date: Sun, 9 Aug 2020 22:15:47 +0300 Subject: [PATCH 248/515] feat(gui): pass "" and display 1 if required_confirmations is null --- atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml | 3 ++- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml index 214f2f5683..931b592848 100644 --- a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml +++ b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml @@ -94,6 +94,7 @@ DefaultModal { id: config_section readonly property var default_config: API.get().trading_pg.get_raw_mm2_coin_cfg(rel_ticker) + readonly property bool is_dpow_configurable: config_section.default_config.requires_notarization || false Layout.bottomMargin: 10 Layout.alignment: Qt.AlignHCenter @@ -112,7 +113,7 @@ DefaultModal { Layout.alignment: Qt.AlignHCenter text_value: API.get().settings_pg.empty_string + ("✅ " + (config_section.is_dpow_configurable ? qsTr("dPoW protected") : - qsTr("%1 confirmations for incoming %2 transactions").arg(config_section.default_config.required_confirmations).arg(rel_ticker))) + qsTr("%1 confirmations for incoming %2 transactions").arg(config_section.default_config.required_confirmations || 1).arg(rel_ticker))) } DefaultText { diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index e81016583c..459e5985ee 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -246,7 +246,7 @@ Item { nota = default_config.requires_notarization ? "1" : "0" } - if(nota !== "1") { + if(nota !== "1" && default_config.required_confirmations !== undefined && default_config.required_confirmations !== null) { confs = default_config.required_confirmations.toString() } } From a1e6faf2002ac204844ee2a1fb88be0d23b3915e Mon Sep 17 00:00:00 2001 From: naezith Date: Mon, 10 Aug 2020 06:59:09 +0300 Subject: [PATCH 249/515] feat(gui): fix price section was wonky after swap --- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index 459e5985ee..638a4f3348 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -211,6 +211,9 @@ Item { if(is_swap) { console.log("Swapping current pair, it was: ", base, rel) API.get().trading_pg.swap_market_pair() + const tmp = base + base = rel + rel = tmp } else { console.log("Setting current orderbook with params: ", base, rel) From 47c69b4ed2feeb0c32d259fe715e16719c197c69 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Mon, 10 Aug 2020 08:42:39 +0200 Subject: [PATCH 250/515] feat(ci): remove libbtc --- .github/workflows/atomicdexpro_ci.yml | 36 ++++++++++++++++----------- CMakeLists.txt | 15 +++++------ main.cpp | 4 +-- src/atomic.dex.app.cpp | 30 ++-------------------- src/atomic.dex.pch.hpp | 11 +------- 5 files changed, 35 insertions(+), 61 deletions(-) diff --git a/.github/workflows/atomicdexpro_ci.yml b/.github/workflows/atomicdexpro_ci.yml index dae9711343..135559ecc2 100644 --- a/.github/workflows/atomicdexpro_ci.yml +++ b/.github/workflows/atomicdexpro_ci.yml @@ -216,6 +216,7 @@ jobs: git \ boost \ gcc \ + gsed \ llvm@9 export CC=/usr/local/opt/llvm@9/bin/clang @@ -230,21 +231,28 @@ jobs: cd ../ # get libbitcoin - git clone --depth 1 --branch version5 --single-branch "https://github.com/libbitcoin/secp256k1" - cd secp256k1 - ./autogen.sh - ./configure --disable-shared --disable-tests --enable-module-recovery - make -j3 - sudo make install - cd ../ + #git clone --depth 1 --branch version5 --single-branch "https://github.com/libbitcoin/secp256k1" + #cd secp256k1 + #./autogen.sh + #./configure --disable-shared --disable-tests --enable-module-recovery + #make -j3 + #sudo make install + #cd ../ + + #git clone --depth 1 --branch version3 --single-branch https://github.com/KomodoPlatform/libbitcoin-system.git + #cd libbitcoin-system + #./autogen.sh + #./configure --with-boost --disable-shared + #make -j3 + #sudo make install + #sudo update_dyld_shared_cache - git clone --depth 1 --branch version3 --single-branch https://github.com/KomodoPlatform/libbitcoin-system.git - cd libbitcoin-system - ./autogen.sh - ./configure --with-boost --disable-shared - make -j3 - sudo make install - sudo update_dyld_shared_cache + git clone https://github.com/KomodoPlatform/libwally-core.git + cd libwally-core + ./tools/autogen.sh + ./configure --disable-shared + sudo make -j3 install + cd .. # get SDKs git clone https://github.com/phracker/MacOSX-SDKs $HOME/sdk diff --git a/CMakeLists.txt b/CMakeLists.txt index e07b118428..a1a80a816b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -100,14 +100,14 @@ find_package(spdlog CONFIG REQUIRED) find_package(Boost REQUIRED COMPONENTS filesystem random) find_package(Qt5 COMPONENTS Core Quick LinguistTools Svg Charts Widgets REQUIRED) find_package(unofficial-sodium CONFIG REQUIRED) -find_library(unofficial-bitcoin-external bitcoin) -find_path(unofficial-btc-headers bitcoin/bitcoin.hpp) -message(STATUS "Found libbtc -> ${unofficial-bitcoin-external} ${unofficial-btc-headers}") +#find_library(unofficial-bitcoin-external bitcoin) +#find_path(unofficial-btc-headers bitcoin/bitcoin.hpp) +#message(STATUS "Found libbtc -> ${unofficial-bitcoin-external} ${unofficial-btc-headers}") add_library(unofficial-bitcoin INTERFACE) -if (APPLE) - target_link_libraries(unofficial-bitcoin INTERFACE ${unofficial-bitcoin-external}) - target_include_directories(unofficial-bitcoin INTERFACE ${unofficial-btc-headers}) -elseif (WIN32) +#if (APPLE) +# target_link_libraries(unofficial-bitcoin INTERFACE ${unofficial-bitcoin-external}) +# target_include_directories(unofficial-bitcoin INTERFACE ${unofficial-btc-headers}) +if (WIN32) target_link_directories(unofficial-bitcoin INTERFACE wally) target_link_libraries(unofficial-bitcoin INTERFACE wally) target_include_directories(unofficial-bitcoin INTERFACE wally) @@ -117,6 +117,7 @@ else () find_path(unofficial-wally-headers wally_core.h) target_link_libraries(unofficial-bitcoin INTERFACE ${unofficial-wally} ${unofficial-secp}) target_include_directories(unofficial-bitcoin INTERFACE ${unofficial-wally-headers}) + message(STATUS "Found wally -> ${unofficial-wally} ${unofficial-wally-headers}") endif () add_library(unofficial-btc::bitcoin ALIAS unofficial-bitcoin) diff --git a/main.cpp b/main.cpp index e4b75193d3..c02bd6107c 100644 --- a/main.cpp +++ b/main.cpp @@ -59,7 +59,7 @@ main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) date::set_install(install_db_tz_path->string()); #endif -#if defined(_WIN32) || defined(WIN32) || defined(__linux__) +#if defined(_WIN32) || defined(WIN32) || defined(__linux__) || defined(__APPLE__) auto wally_res = wally_init(0); assert(wally_res == WALLY_OK); #endif @@ -156,7 +156,7 @@ main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) atomic_app.launch(); auto res = app->exec(); -#if defined(_WIN32) || defined(WIN32) || defined(__linux__) +#if defined(_WIN32) || defined(WIN32) || defined(__linux__) || defined(__APPLE__) auto wallet_exit_res = wally_cleanup(0); assert(wallet_exit_res == WALLY_OK); #endif diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index 20714fbc39..73efb786fc 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -162,15 +162,7 @@ namespace atomic_dex QString atomic_dex::application::get_mnemonic() { -#ifdef __APPLE__ - bc::data_chunk my_entropy_256(32); // 32 bytes = 256 bits - - bc::pseudo_random_fill(my_entropy_256); - - // Instantiate mnemonic word_list - bc::wallet::word_list words = bc::wallet::create_mnemonic(my_entropy_256); - return QString::fromStdString(bc::join(words)); -#elif defined(_WIN32) || defined(WIN32) +#if defined(_WIN32) || defined(WIN32) std::array data; sysrandom(data.data(), data.size()); char* output; @@ -824,25 +816,7 @@ namespace atomic_dex bool application::mnemonic_validate(const QString& entropy) { -#ifdef __APPLE__ - std::vector mnemonic; - - // Split - std::string s = entropy.toStdString(); - const std::string delimiter = " "; - size_t pos = 0; - while ((pos = s.find(delimiter)) != std::string::npos) - { - mnemonic.emplace_back(s.substr(0, pos)); - s.erase(0, pos + delimiter.length()); - } - mnemonic.emplace_back(s); - - // Validate - return bc::wallet::validate_mnemonic(mnemonic); -#else return bip39_mnemonic_validate(nullptr, entropy.toStdString().c_str()) == 0; -#endif } bool @@ -1219,7 +1193,7 @@ namespace atomic_dex assert(ptr != nullptr); return ptr; } -} +} // namespace atomic_dex //! Notification namespace atomic_dex diff --git a/src/atomic.dex.pch.hpp b/src/atomic.dex.pch.hpp index ce159a40e5..8554972af7 100644 --- a/src/atomic.dex.pch.hpp +++ b/src/atomic.dex.pch.hpp @@ -158,16 +158,7 @@ adjust_precision(const std::string& current) #include ///< ranges::view::ints #include ///< ranges::view::zip -#ifdef __APPLE__ -//! Other dependencies Headers -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wunused-function" -# pragma clang diagnostic ignored "-Wunused-parameter" -# pragma clang diagnostic ignored "-Wignored-qualifiers" -# include -# include -# pragma clang diagnostic pop -#elif defined(_WIN32) || defined(WIN32) +#if defined(_WIN32) || defined(WIN32) # include #else # include From 76c44294822533e8e59bc41a2ad598c1c779558b Mon Sep 17 00:00:00 2001 From: romanszterg Date: Mon, 10 Aug 2020 08:46:44 +0200 Subject: [PATCH 251/515] feat(ci): add gnu-sed --- .github/workflows/atomicdexpro_ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/atomicdexpro_ci.yml b/.github/workflows/atomicdexpro_ci.yml index 135559ecc2..0cd814a91d 100644 --- a/.github/workflows/atomicdexpro_ci.yml +++ b/.github/workflows/atomicdexpro_ci.yml @@ -216,7 +216,7 @@ jobs: git \ boost \ gcc \ - gsed \ + gnu-sed \ llvm@9 export CC=/usr/local/opt/llvm@9/bin/clang From 75218d62aea94f54784299019e2ecb38c1717bf1 Mon Sep 17 00:00:00 2001 From: "Anton \"TonyL\" Lysakov" Date: Mon, 10 Aug 2020 16:30:17 +0700 Subject: [PATCH 252/515] (opsec)use own forks for ci deps --- .github/workflows/atomicdexpro_ci.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/atomicdexpro_ci.yml b/.github/workflows/atomicdexpro_ci.yml index dae9711343..193a1689ef 100644 --- a/.github/workflows/atomicdexpro_ci.yml +++ b/.github/workflows/atomicdexpro_ci.yml @@ -19,7 +19,7 @@ jobs: submodules: 'true' - name: Install QT (Linux) - uses: jurplel/install-qt-action@v2 + uses: KomodoPlatform/install-qt-action@v2 with: version: '5.15.0' host: 'linux' @@ -30,7 +30,7 @@ jobs: py7zrversion: '==0.6' - name: Setup Nim (Linux) - uses: jiro4989/setup-nim-action@v1.0.2 + uses: KomodoPlatform/setup-nim-action@v1.0.2 with: nim-version: '1.2.0' @@ -123,7 +123,7 @@ jobs: LDFLAGS: -stdlib=libc++ CXX: clang++-9 CC: clang-9 - uses: lukka/run-vcpkg@v3 + uses: KomodoPlatform/run-vcpkg@v3 with: vcpkgArguments: '@${{ github.workspace }}/.github/workflows/linux_response_file.txt' vcpkgDirectory: '${{ github.workspace }}/ci_tools_atomic_dex/vcpkg-repo' @@ -195,7 +195,7 @@ jobs: - name: Install QT (MacOS) if: steps.cache-qt-mac.outputs.cache-hit != 'true' - uses: jurplel/install-qt-action@v2 + uses: KomodoPlatform/install-qt-action@v2 with: version: '5.15.0' host: 'mac' @@ -253,7 +253,7 @@ jobs: env: # Or as an environment variable CXX: /usr/local/opt/llvm@9/bin/clang++ CC: /usr/local/opt/llvm@9/bin/clang - uses: lukka/run-vcpkg@v3 + uses: KomodoPlatform/run-vcpkg@v3 with: vcpkgArguments: '@${{ github.workspace }}/.github/workflows/osx_response_file.txt' vcpkgDirectory: '${{ github.workspace }}/ci_tools_atomic_dex/vcpkg-repo' @@ -302,7 +302,7 @@ jobs: submodules: 'true' - name: Install QT (Win) - uses: jurplel/install-qt-action@v2 + uses: KomodoPlatform/install-qt-action@v2 with: version: '5.15.0' host: 'windows' @@ -312,7 +312,7 @@ jobs: modules: 'qtcharts qtwidgets debug_info' - name: vcpkg deps (Windows) - uses: lukka/run-vcpkg@v3 + uses: KomodoPlatform/run-vcpkg@v3 with: vcpkgArguments: '@${{ github.workspace }}/.github/workflows/windows_response_file.txt' vcpkgDirectory: '${{ github.workspace }}/ci_tools_atomic_dex/vcpkg-repo' From 267bf0aee1e6ca628946d7fab037fe900a71d862 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Mon, 10 Aug 2020 14:17:31 +0200 Subject: [PATCH 253/515] feat(version): bump to 0.2.1 --- CMakeLists.txt | 2 +- assets/config/{0.2.0-coins.json => 0.2.1-coins.json} | 0 src/atomic.dex.version.hpp | 6 +++--- 3 files changed, 4 insertions(+), 4 deletions(-) rename assets/config/{0.2.0-coins.json => 0.2.1-coins.json} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index a1a80a816b..b70ee6a755 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5) -project(atomic_qt LANGUAGES CXX VERSION 0.2.0) +project(atomic_qt LANGUAGES CXX VERSION 0.2.1) set(CMAKE_INCLUDE_CURRENT_DIR ON) diff --git a/assets/config/0.2.0-coins.json b/assets/config/0.2.1-coins.json similarity index 100% rename from assets/config/0.2.0-coins.json rename to assets/config/0.2.1-coins.json diff --git a/src/atomic.dex.version.hpp b/src/atomic.dex.version.hpp index 1a0106f600..158b9d9947 100644 --- a/src/atomic.dex.version.hpp +++ b/src/atomic.dex.version.hpp @@ -21,18 +21,18 @@ namespace atomic_dex constexpr const char* get_version() { - return "0.2.0-alpha"; + return "0.2.1-alpha"; } constexpr const char* get_raw_version() { - return "0.2.0"; + return "0.2.1"; } constexpr const char* get_precedent_raw_version() { - return "0.1.5"; + return "0.2.0"; } } // namespace atomic_dex From 48897c769dc0556d8a031ca98fb79f9a83f93dd7 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Mon, 10 Aug 2020 14:31:56 +0200 Subject: [PATCH 254/515] feat(version): bump to 0.2.1 --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b70ee6a755..bd49d15c0f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,13 +47,13 @@ endif () ##! We fetch our dependence if (APPLE) FetchContent_Declare(mm2 - URL https://github.com/KomodoPlatform/atomicDEX-API/releases/download/beta-2.0.2165/mm2-e51a128c6-Darwin-Release.zip) + URL https://github.com/KomodoPlatform/atomicDEX-API/releases/download/beta-2.0.2232/mm2-20c8e11d6-Darwin-Release.zip) elseif (UNIX AND NOT APPLE) FetchContent_Declare(mm2 - URL https://github.com/KomodoPlatform/atomicDEX-API/releases/download/beta-2.0.2165/mm2-e51a128c6-Linux-Release.zip) + URL https://github.com/KomodoPlatform/atomicDEX-API/releases/download/beta-2.0.2232/mm2-20c8e11d6-Linux-Release.zip) else () FetchContent_Declare(mm2 - URL https://github.com/KomodoPlatform/atomicDEX-API/releases/download/beta-2.0.2165/mm2-e51a128c6-Windows_NT-Release.zip) + URL https://github.com/KomodoPlatform/atomicDEX-API/releases/download/beta-2.0.2232/mm2-20c8e11d6-Windows_NT-Release.zip) endif () FetchContent_Declare(jl777-coins From 9ead7ec5e4b13fd12b4c2fa27a9fa654cf8055e8 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Mon, 10 Aug 2020 18:39:13 +0200 Subject: [PATCH 255/515] feat(verbosre_claim_rewards): add rpc_kmd_rewards_info --- src/atomic.dex.mm2.api.cpp | 35 +++++++++++++++++++++++++++++++++++ src/atomic.dex.mm2.api.hpp | 8 ++++++++ 2 files changed, 43 insertions(+) diff --git a/src/atomic.dex.mm2.api.cpp b/src/atomic.dex.mm2.api.cpp index 04f2283f20..10e0459401 100644 --- a/src/atomic.dex.mm2.api.cpp +++ b/src/atomic.dex.mm2.api.cpp @@ -1098,6 +1098,41 @@ namespace mm2::api return "error occured during rpc_version"; } + kmd_rewards_info_answer + rpc_kmd_rewards_info() + { + spdlog::info("Processing rpc call: kmd_rewards_info"); + kmd_rewards_info_answer out; + + nlohmann::json json_data = template_request("kmd_rewards_info"); + RestClient::Response resp; + + auto json_copy = json_data; + json_copy["userpass"] = "*******"; + spdlog::debug("{} request: {}", __FUNCTION__, json_copy.dump()); + + resp = RestClient::post(g_endpoint, "application/json", json_data.dump()); + out.rpc_result_code = resp.code; + out.result = nlohmann::json::parse(resp.body); + if (resp.code == 200) + { + for (auto&& obj: out.result.at("result")) + { + if (obj.contains("accrue_stop_at")) + { + std::size_t accrue_timestamp = obj.at("accrue_stop_at").get(); + obj["accrue_stop_at_human_date"] = to_human_date(accrue_timestamp, "%e %b %Y, %I:%M"); + } + if (obj.contains("locktime")) + { + std::size_t locktime_timestamp = obj.at("locktime").get(); + obj["locktime_human_date"] = to_human_date(locktime_timestamp, "%e %b %Y, %I:%M"); + } + } + } + return out; + } + nlohmann::json rpc_batch_electrum(std::vector requests) { diff --git a/src/atomic.dex.mm2.api.hpp b/src/atomic.dex.mm2.api.hpp index df1a617bb6..4834375182 100644 --- a/src/atomic.dex.mm2.api.hpp +++ b/src/atomic.dex.mm2.api.hpp @@ -692,6 +692,14 @@ namespace mm2::api my_recent_swaps_answer rpc_my_recent_swaps(my_recent_swaps_request&& request); + struct kmd_rewards_info_answer + { + nlohmann::json result; + int rpc_result_code; + }; + + kmd_rewards_info_answer rpc_kmd_rewards_info(); + nlohmann::json rpc_batch_electrum(std::vector requests); nlohmann::json rpc_batch_enable(std::vector requests); From d3d165174838d773589e05b4bd131453d4612e33 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Mon, 10 Aug 2020 21:46:18 +0200 Subject: [PATCH 256/515] feat(verbosre_claim_rewards): change backend claim verbose kmd rewards --- src/atomic.dex.app.cpp | 15 +++------------ src/atomic.dex.app.hpp | 2 +- src/atomic.dex.mm2.cpp | 13 ++++++++++--- src/atomic.dex.mm2.hpp | 3 +-- 4 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index 73efb786fc..7c8ec20bdb 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -484,24 +484,15 @@ namespace atomic_dex return get_mm2().is_claiming_ready(ticker.toStdString()); } - QObject* + QVariant atomic_dex::application::claim_rewards(const QString& ticker) { std::error_code ec; auto answer = get_mm2().claim_rewards(ticker.toStdString(), ec); - if (not answer.error.has_value()) - { - if (ec) - { - answer.error = ec.message(); - } - } - - const auto coin = get_mm2().get_coin_info(m_coin_info->get_ticker().toStdString()); - QObject* obj = to_qt_binding(std::move(answer), this, QString::fromStdString(coin.explorer_url[0])); + answer["explorer_url"] = get_mm2().get_coin_info(m_coin_info->get_ticker().toStdString()).explorer_url[0]; - return obj; + return nlohmann_json_object_to_qt_json_object(answer); } QString diff --git a/src/atomic.dex.app.hpp b/src/atomic.dex.app.hpp index c04064d25c..28d3988ac2 100644 --- a/src/atomic.dex.app.hpp +++ b/src/atomic.dex.app.hpp @@ -201,7 +201,7 @@ namespace atomic_dex Q_INVOKABLE bool do_i_have_enough_funds(const QString& ticker, const QString& amount) const; Q_INVOKABLE bool disable_coins(const QStringList& coins); Q_INVOKABLE bool is_claiming_ready(const QString& ticker); - Q_INVOKABLE QObject* claim_rewards(const QString& ticker); + Q_INVOKABLE QVariant claim_rewards(const QString& ticker); Q_INVOKABLE QString get_cex_rates(const QString& base, const QString& rel); diff --git a/src/atomic.dex.mm2.cpp b/src/atomic.dex.mm2.cpp index d98150c780..670a289972 100644 --- a/src/atomic.dex.mm2.cpp +++ b/src/atomic.dex.mm2.cpp @@ -1046,11 +1046,13 @@ namespace atomic_dex return false; } - t_withdraw_answer + nlohmann::json mm2::claim_rewards(const std::string& ticker, t_mm2_ec& ec) noexcept { spdlog::debug("{} l{} f[{}]", __FUNCTION__, __LINE__, fs::path(__FILE__).filename().string()); - const auto& info = get_coin_info(ticker); + + nlohmann::json out = nlohmann::json::object(); + const auto& info = get_coin_info(ticker); if (not info.is_claimable || not do_i_have_enough_funds(ticker, t_float_50(info.minimal_claim_amount))) { ec = not info.is_claimable ? dextop_error::ticker_is_not_claimable : dextop_error::claim_not_enough_funds; @@ -1058,7 +1060,12 @@ namespace atomic_dex } t_withdraw_request req{.coin = ticker, .to = m_balance_informations.at(ticker).address, .amount = "0", .max = true}; auto answer = ::mm2::api::rpc_withdraw(std::move(req)); - return answer; + if (answer.rpc_result_code == 200) + { + out["withdraw_answer"] = nlohmann::json::parse(answer.raw_result); + out["kmd_rewards_info"] = ::mm2::api::rpc_kmd_rewards_info().result; + } + return out; } t_broadcast_answer diff --git a/src/atomic.dex.mm2.hpp b/src/atomic.dex.mm2.hpp index 2ded366e1c..5dc930191e 100644 --- a/src/atomic.dex.mm2.hpp +++ b/src/atomic.dex.mm2.hpp @@ -216,7 +216,7 @@ namespace atomic_dex [[nodiscard]] bool is_claiming_ready(const std::string& ticker) const noexcept; //! Claim rewards - t_withdraw_answer claim_rewards(const std::string& ticker, t_mm2_ec& ec) noexcept; + nlohmann::json claim_rewards(const std::string& ticker, t_mm2_ec& ec) noexcept; //! Send Rewards t_broadcast_answer send_rewards(t_broadcast_request&& req, t_mm2_ec& ec) noexcept; @@ -243,7 +243,6 @@ namespace atomic_dex [[nodiscard]] t_get_trade_fee_answer get_trade_fixed_fee(const std::string& ticker) const; void apply_erc_fees(const std::string& ticker, t_float_50& value); - ; //! Get Current orderbook [[nodiscard]] t_orderbook_answer get_orderbook(t_mm2_ec& ec) const noexcept; From 3bc0a1c8c4055aca128b72ff16446cca836912b1 Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 11 Aug 2020 03:26:56 +0300 Subject: [PATCH 257/515] feat(gui): fix cex price expedient/expensive part showing false values --- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index 638a4f3348..fdcba3686c 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -196,15 +196,13 @@ Item { // Check if it's a swap if(base !== changed_ticker && rel === changed_ticker) is_swap = true - - base = changed_ticker + else base = changed_ticker } else { // Check if it's a swap if(rel !== changed_ticker && base === changed_ticker) is_swap = true - - rel = changed_ticker + else rel = changed_ticker } } From 9a6aedd1ae7648b66d6e00162918f8084b7a7a63 Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 11 Aug 2020 04:06:34 +0300 Subject: [PATCH 258/515] feat(gui): fix window was not maximizing at tray icon click after minimized --- .../qml/Dashboard/NotificationsPanel.qml | 20 ++++++++++++++++++- atomic_qt_design/qml/main.qml | 11 +++++++++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml index fa11ef07bd..795b2d5d5e 100644 --- a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml +++ b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml @@ -15,8 +15,26 @@ FloatingBackground { visible = false } + Timer { + interval: 500 + repeat: true + running: true + onTriggered: { + console.log("Window Visibility:", window.visibility) + } + } + function showApp() { - window.show() + console.log("Show application, visibility:", window.true_visibility) + switch(window.true_visibility) { + case 4: + window.showMaximized() + break + default: + window.show() + break + } + window.raise() window.requestActivate() } diff --git a/atomic_qt_design/qml/main.qml b/atomic_qt_design/qml/main.qml index 2c1baf243a..2fee9174b9 100644 --- a/atomic_qt_design/qml/main.qml +++ b/atomic_qt_design/qml/main.qml @@ -15,7 +15,16 @@ Window { Component.onCompleted: showMaximized() - onVisibilityChanged: API.get().change_state(visibility) + property int true_visibility + + onVisibilityChanged: { + // 3 is minimized, ignore that + if(visibility !== 3) + true_visibility = visibility + + API.get().change_state(visibility) + } + App { anchors.fill: parent } From 0c7f4331fa64f65329ee194bd31f81cb2c92f24e Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 11 Aug 2020 04:43:49 +0300 Subject: [PATCH 259/515] feat(gui): fix tray icon click breaking fullscreen on mac --- .../qml/Dashboard/NotificationsPanel.qml | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml index 795b2d5d5e..118cd33462 100644 --- a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml +++ b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml @@ -15,21 +15,14 @@ FloatingBackground { visible = false } - Timer { - interval: 500 - repeat: true - running: true - onTriggered: { - console.log("Window Visibility:", window.visibility) - } - } - function showApp() { - console.log("Show application, visibility:", window.true_visibility) switch(window.true_visibility) { case 4: window.showMaximized() break + case 5: + window.showFullScreen() + break default: window.show() break From 821a851904cc0e012353071b55e9a2fb6588cc3e Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 11 Aug 2020 05:15:11 +0300 Subject: [PATCH 260/515] feat(gui): remove the unnecessary `change required confirmations` switch --- .../qml/Exchange/Trade/ConfirmTradeModal.qml | 33 ++++++------------- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 4 +-- 2 files changed, 12 insertions(+), 25 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml index 931b592848..d8d24f9957 100644 --- a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml +++ b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml @@ -151,10 +151,6 @@ DefaultModal { visible: config_section.is_dpow_configurable checked: true - onCheckedChanged: { - if(checked) enable_normal_confs.checked = true - } - text: API.get().settings_pg.empty_string + (qsTr("Enable Komodo dPoW security")) } @@ -169,34 +165,28 @@ DefaultModal { linkColor: color } - // Normal configuration switch - Switch { - id: enable_normal_confs + // Normal configuration settings + ColumnLayout { Layout.alignment: Qt.AlignHCenter - visible: !config_section.is_dpow_configurable || !enable_dpow_confs.checked enabled: !config_section.is_dpow_configurable || !enable_dpow_confs.checked - checked: true - text: API.get().settings_pg.empty_string + (qsTr("Change required confirmations")) - } - - // Normal configuration settings - ColumnLayout { - Layout.alignment: Qt.AlignHCenter - visible: enable_normal_confs.visible && enable_normal_confs.checked - enabled: enable_normal_confs.enabled && enable_normal_confs.checked + HorizontalLine { + Layout.topMargin: 10 + Layout.bottomMargin: 10 + Layout.fillWidth: true + } DefaultText { Layout.alignment: Qt.AlignHCenter - text_value: API.get().settings_pg.empty_string + (qsTr("Confirmations") + ": " + required_confirmation_count.value) + text_value: API.get().settings_pg.empty_string + (qsTr("Required Confirmations") + ": " + required_confirmation_count.value) color: parent.enabled ? Style.colorText : Style.colorTextDisabled } Slider { + id: required_confirmation_count readonly property int default_confirmation_count: 3 Layout.alignment: Qt.AlignHCenter - id: required_confirmation_count stepSize: 1 from: 1 to: 5 @@ -247,10 +237,7 @@ DefaultModal { enable_custom_config: enable_custom_config.checked, is_dpow_configurable: config_section.is_dpow_configurable, enable_dpow_confs: enable_dpow_confs.checked, - enable_normal_confs: enable_normal_confs.checked, - normal_configuration: { - required_confirmation_count: required_confirmation_count.value - }, + required_confirmation_count: required_confirmation_count.value, }, config_section.default_config) root.close() diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index fdcba3686c..f67c790fa7 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -238,8 +238,8 @@ Item { nota = options.enable_dpow_confs ? "1" : "0" } - if(nota !== "1" && options.enable_normal_confs) { - confs = options.normal_configuration.required_confirmation_count.toString() + if(nota !== "1") { + confs = options.required_confirmation_count.toString() } } else { From d9275e1b06dad17c816ef771f0f5da1280efe640 Mon Sep 17 00:00:00 2001 From: smk762 <35845239+smk762@users.noreply.github.com> Date: Tue, 11 Aug 2020 18:41:34 +0800 Subject: [PATCH 261/515] Update 0.2.1-coins.json --- assets/config/0.2.1-coins.json | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/assets/config/0.2.1-coins.json b/assets/config/0.2.1-coins.json index c27ac34596..2b9e2bf83c 100644 --- a/assets/config/0.2.1-coins.json +++ b/assets/config/0.2.1-coins.json @@ -222,8 +222,9 @@ } ], "explorer_url": [ - "https://explorer.dash.org/" + "https://blockchair.com/dash/" ], + "explorer_tx_url":"https://blockchair.com/dash/transaction/", "is_erc_20": false, "type": "UTXO" }, @@ -316,6 +317,8 @@ "explorer_url": [ "https://chainz.cryptoid.info/emc2/" ], + "explorer_tx_url":"https://chainz.cryptoid.info/emc2/tx.dws?", + "explorer_address_url":"https://chainz.cryptoid.info/emc2/address.dws?", "type": "UTXO", "is_erc_20": false, "active": false, @@ -762,7 +765,7 @@ } ], "explorer_url": [ - "https://explorer.chips.cash/" + "http://chips.komodochainz.info/" ], "active": false, "currently_enabled": false @@ -855,7 +858,7 @@ } ], "explorer_url": [ - "https://explorer.ilien.io/" + "https://iln.explorer.dexstats.info/" ], "active": false, "currently_enabled": false From 9c9d01651fac0986ff9f8a3322bcad2e32f08059 Mon Sep 17 00:00:00 2001 From: smk762 <35845239+smk762@users.noreply.github.com> Date: Tue, 11 Aug 2020 20:06:48 +0800 Subject: [PATCH 262/515] Update 0.2.1-coins.json --- assets/config/0.2.1-coins.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/assets/config/0.2.1-coins.json b/assets/config/0.2.1-coins.json index 2b9e2bf83c..a9304a84d4 100644 --- a/assets/config/0.2.1-coins.json +++ b/assets/config/0.2.1-coins.json @@ -224,7 +224,7 @@ "explorer_url": [ "https://blockchair.com/dash/" ], - "explorer_tx_url":"https://blockchair.com/dash/transaction/", + "explorer_tx_url":"transaction/", "is_erc_20": false, "type": "UTXO" }, @@ -317,8 +317,8 @@ "explorer_url": [ "https://chainz.cryptoid.info/emc2/" ], - "explorer_tx_url":"https://chainz.cryptoid.info/emc2/tx.dws?", - "explorer_address_url":"https://chainz.cryptoid.info/emc2/address.dws?", + "explorer_tx_url":"tx.dws?", + "explorer_address_url":"address.dws?", "type": "UTXO", "is_erc_20": false, "active": false, From a1ef7409d06729c538c45dd931ba961df48da3e7 Mon Sep 17 00:00:00 2001 From: cipig Date: Tue, 11 Aug 2020 16:12:30 +0000 Subject: [PATCH 263/515] add Hempcoin(THC) --- assets/config/0.2.1-coins.json | 21 +++++++++++++++++++ atomic_qt_design/assets/images/coins/thc.png | Bin 0 -> 8250 bytes qml.qrc | 1 + 3 files changed, 22 insertions(+) create mode 100644 atomic_qt_design/assets/images/coins/thc.png diff --git a/assets/config/0.2.1-coins.json b/assets/config/0.2.1-coins.json index c27ac34596..5b5f4f49b7 100644 --- a/assets/config/0.2.1-coins.json +++ b/assets/config/0.2.1-coins.json @@ -953,6 +953,27 @@ "active": false, "currently_enabled": false }, + "THC": { + "coin": "THC", + "name": "HempCoin", + "coinpaprika_id": "thc-hempcoin", + "coingecko_id": "hempcoin-thc", + "electrum": [ + { + "url": "165.22.52.123:10022" + }, + { + "url": "157.230.45.184:10022" + } + ], + "explorer_url": [ + "https://thc.explorer.dexstats.info/" + ], + "type": "Smart Chain", + "is_erc_20": false, + "active": false, + "currently_enabled": false + }, "XZC": { "coin": "XZC", "name": "Zcoin", diff --git a/atomic_qt_design/assets/images/coins/thc.png b/atomic_qt_design/assets/images/coins/thc.png new file mode 100644 index 0000000000000000000000000000000000000000..2e88a38562fa37f8c8f50f058a130f86913e084b GIT binary patch literal 8250 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/assets/images/coins/qtum.png atomic_qt_design/assets/images/coins/rvn.png atomic_qt_design/assets/images/coins/supernet.png + atomic_qt_design/assets/images/coins/thc.png atomic_qt_design/assets/images/coins/usdc.png atomic_qt_design/assets/images/coins/vrsc.png atomic_qt_design/assets/images/coins/vote2020.png From f86ae5c3a9d447468478d77478cef4820bbebf7b Mon Sep 17 00:00:00 2001 From: cipig Date: Tue, 11 Aug 2020 16:27:25 +0000 Subject: [PATCH 264/515] replace old logo --- atomic_qt_design/assets/images/coins/thc.png | Bin 8250 -> 5745 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/atomic_qt_design/assets/images/coins/thc.png b/atomic_qt_design/assets/images/coins/thc.png index 2e88a38562fa37f8c8f50f058a130f86913e084b..7c536e8ecbc65457a483758355d2ac9d6f87679f 100644 GIT binary patch literal 5745 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 literal 8250 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 Date: Tue, 11 Aug 2020 20:00:53 +0300 Subject: [PATCH 265/515] feat(gui): make claim rewards functional again --- .../qml/Wallet/ClaimRewardsModal.qml | 38 ++++++++++++++++--- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml index 07f42fb099..d811d9046c 100644 --- a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml +++ b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml @@ -8,7 +8,31 @@ import "../Constants" DefaultModal { id: root - readonly property var default_prepare_claim_rewards_result: ({ has_error: false, error_message: "", tx_hex: "", date: "", balance_change: "", fees:"", explorer_url: ""}) + readonly property var default_prepare_claim_rewards_result: ({ + "kmd_rewards_info": { + "result": [ + { + "accrue_start_at": 1596785618, + "accrue_stop_at": 1599460418, + "accrue_start_at_human_date": " 7 Aug 2020, 08:33", + "accrue_stop_at_human_date": " 7 Sep 2020, 08:33", + "accrued_rewards": { + "Accrued": "0.04973265" + }, + "amount": "103.62356229", + "output_index": 0 + } + ] + }, + "withdraw_answer": { + "fee_details": { + "amount": "0.00001" + }, + "my_balance_change": "0.04972265", + "tx_hash": "45f7a75e9782998f3a0809ea9ec8b68d3bdc438d34b6fc4114a6c8eddc3be6ae", + "tx_hex": "0400008085202f8901bc8f81d43c4133f5ffe68d5f07c6dcf785d34b2bb184f91bdb6e990bd8ab0977000000006a473044022014b3f1dbca1e28c5958f94cf5d1aa97b3d49f53d2409baefb2cc882f3883eb3a02200d26f5deafdb6e0475d4b50764e1c77a69872413e75576beeba993a1d63225f3012102d4acb3b1cc944b8b44836c6a4ef87bdee906ce268465bde8106cfee171b7f40dffffffff01eee0f069020000001976a914eed5d3ad264ffc68fc0a6454e1696a30d8f405be88ac1aa3315f000000000000000000000000000000" + } + }) property var prepare_claim_rewards_result: default_prepare_claim_rewards_result property string send_result @@ -28,8 +52,12 @@ DefaultModal { prepare_claim_rewards_result = API.get().claim_rewards(API.get().current_coin_info.ticker) console.log(JSON.stringify(prepare_claim_rewards_result)) - if(prepare_claim_rewards_result.has_error) { - toast.show(qsTr("Failed to prepare to claim rewards"), General.time_toast_important_error, prepare_claim_rewards_result.error_message) + if(prepare_claim_rewards_result.withdraw_answer.error) { + toast.show(qsTr("Failed to prepare to claim rewards"), General.time_toast_important_error, prepare_claim_rewards_result.withdraw_answer.error) + return false + } + else if(prepare_claim_rewards_result.kmd_rewards_info.error) { + toast.show(qsTr("Failed to get the rewards info"), General.time_toast_important_error, prepare_claim_rewards_result.kmd_rewards_info.error) return false } else { @@ -39,7 +67,7 @@ DefaultModal { } function claimRewards() { - send_result = API.get().send_rewards(prepare_claim_rewards_result.tx_hex) + send_result = API.get().send_rewards(prepare_claim_rewards_result.withdraw_answer.tx_hex) stack_layout.currentIndex = 1 postClaim() } @@ -67,7 +95,7 @@ DefaultModal { DefaultText { visible: text_error.text === "" - text_value: API.get().settings_pg.empty_string + (qsTr("You will receive %1", "AMT TICKER").arg(General.formatCrypto("", prepare_claim_rewards_result.balance_change, API.get().current_coin_info.ticker))) + text_value: API.get().settings_pg.empty_string + (qsTr("You will receive %1", "AMT TICKER").arg(General.formatCrypto("", prepare_claim_rewards_result.withdraw_answer.my_balance_change, API.get().current_coin_info.ticker))) } DefaultText { From 6e7723cf19a8884e57904954d19f555a47f4eb43 Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 11 Aug 2020 20:09:50 +0300 Subject: [PATCH 266/515] feat(gui): upgrade qtquick 2.12 to 2.14 --- atomic_qt_design/qml/Components/AddressField.qml | 2 +- atomic_qt_design/qml/Components/AddressFieldWithTitle.qml | 2 +- atomic_qt_design/qml/Components/AmountField.qml | 2 +- atomic_qt_design/qml/Components/AmountFieldWithInfo.qml | 2 +- atomic_qt_design/qml/Components/AmountIntField.qml | 2 +- atomic_qt_design/qml/Components/Arrow.qml | 2 +- atomic_qt_design/qml/Components/CexInfoTrigger.qml | 2 +- atomic_qt_design/qml/Components/Circle.qml | 2 +- atomic_qt_design/qml/Components/ColumnHeader.qml | 2 +- atomic_qt_design/qml/Components/ComboBoxWithTitle.qml | 2 +- atomic_qt_design/qml/Components/CopyFieldButton.qml | 2 +- atomic_qt_design/qml/Components/DangerButton.qml | 2 +- atomic_qt_design/qml/Components/DefaultBusyIndicator.qml | 2 +- atomic_qt_design/qml/Components/DefaultButton.qml | 2 +- atomic_qt_design/qml/Components/DefaultCheckBox.qml | 2 +- atomic_qt_design/qml/Components/DefaultComboBox.qml | 2 +- atomic_qt_design/qml/Components/DefaultFlickable.qml | 2 +- atomic_qt_design/qml/Components/DefaultImage.qml | 2 +- atomic_qt_design/qml/Components/DefaultInnerShadow.qml | 2 +- atomic_qt_design/qml/Components/DefaultListView.qml | 2 +- atomic_qt_design/qml/Components/DefaultModal.qml | 2 +- atomic_qt_design/qml/Components/DefaultRectangle.qml | 2 +- atomic_qt_design/qml/Components/DefaultScrollBar.qml | 2 +- atomic_qt_design/qml/Components/DefaultText.qml | 2 +- atomic_qt_design/qml/Components/DefaultTextArea.qml | 2 +- atomic_qt_design/qml/Components/DefaultTextField.qml | 2 +- atomic_qt_design/qml/Components/EulaModal.qml | 2 +- atomic_qt_design/qml/Components/FloatingBackground.qml | 2 +- atomic_qt_design/qml/Components/GradientRectangle.qml | 2 +- atomic_qt_design/qml/Components/HideFieldButton.qml | 2 +- atomic_qt_design/qml/Components/HorizontalLine.qml | 2 +- atomic_qt_design/qml/Components/InnerBackground.qml | 2 +- atomic_qt_design/qml/Components/LogModal.qml | 2 +- atomic_qt_design/qml/Components/ModalHeader.qml | 2 +- atomic_qt_design/qml/Components/PasswordField.qml | 2 +- atomic_qt_design/qml/Components/PasswordForm.qml | 2 +- atomic_qt_design/qml/Components/PlusButton.qml | 2 +- atomic_qt_design/qml/Components/PrimaryButton.qml | 2 +- atomic_qt_design/qml/Components/RightClickMenu.qml | 2 +- atomic_qt_design/qml/Components/Separator.qml | 2 +- atomic_qt_design/qml/Components/SetupPage.qml | 2 +- atomic_qt_design/qml/Components/SidebarPanel.qml | 2 +- atomic_qt_design/qml/Components/TextAreaWithTitle.qml | 2 +- atomic_qt_design/qml/Components/TextFieldWithTitle.qml | 2 +- atomic_qt_design/qml/Components/TextWithTitle.qml | 2 +- atomic_qt_design/qml/Components/Toast.qml | 2 +- atomic_qt_design/qml/Components/ToastManager.qml | 2 +- atomic_qt_design/qml/Components/UpdateModal.qml | 2 +- atomic_qt_design/qml/Components/UpdateNotificationLine.qml | 2 +- atomic_qt_design/qml/Components/VerticalLine.qml | 2 +- atomic_qt_design/qml/Components/VerticalLineBasic.qml | 2 +- atomic_qt_design/qml/Components/WalletNameField.qml | 2 +- atomic_qt_design/qml/Exchange/Exchange.qml | 2 +- atomic_qt_design/qml/Exchange/ExchangeTab.qml | 2 +- atomic_qt_design/qml/Exchange/History/History.qml | 2 +- atomic_qt_design/qml/Exchange/History/SwapList.qml | 2 +- atomic_qt_design/qml/Exchange/OrderContent.qml | 2 +- atomic_qt_design/qml/Exchange/OrderLine.qml | 2 +- atomic_qt_design/qml/Exchange/OrderModal.qml | 2 +- atomic_qt_design/qml/Exchange/Orders/OrderList.qml | 2 +- atomic_qt_design/qml/Exchange/Orders/Orders.qml | 2 +- atomic_qt_design/qml/Exchange/Trade/OrderForm.qml | 2 +- atomic_qt_design/qml/Exchange/Trade/Orderbook.qml | 2 +- atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml | 2 +- atomic_qt_design/qml/Exchange/Trade/PriceLine.qml | 2 +- atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml | 2 +- atomic_qt_design/qml/NoConnection.qml | 2 +- atomic_qt_design/qml/Portfolio/Portfolio.qml | 2 +- atomic_qt_design/qml/Screens/Dashboard.qml | 2 +- atomic_qt_design/qml/Screens/FirstLaunch.qml | 2 +- atomic_qt_design/qml/Screens/InitialLoading.qml | 2 +- atomic_qt_design/qml/Screens/Login.qml | 2 +- atomic_qt_design/qml/Screens/NewUser.qml | 2 +- atomic_qt_design/qml/Screens/RecoverSeed.qml | 2 +- atomic_qt_design/qml/Settings/DeleteWalletModal.qml | 2 +- atomic_qt_design/qml/Settings/Languages.qml | 2 +- atomic_qt_design/qml/Settings/RecoverSeedModal.qml | 2 +- atomic_qt_design/qml/Settings/Settings.qml | 2 +- atomic_qt_design/qml/Sidebar/Sidebar.qml | 2 +- atomic_qt_design/qml/Sidebar/SidebarBottom.qml | 2 +- atomic_qt_design/qml/Sidebar/SidebarCenter.qml | 2 +- atomic_qt_design/qml/Sidebar/SidebarLine.qml | 2 +- atomic_qt_design/qml/Wallet/AddressBook.qml | 2 +- atomic_qt_design/qml/Wallet/AddressList.qml | 2 +- atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml | 4 +++- atomic_qt_design/qml/Wallet/CoinList.qml | 2 +- atomic_qt_design/qml/Wallet/EnableCoinModal.qml | 2 +- atomic_qt_design/qml/Wallet/PriceGraph.qml | 2 +- atomic_qt_design/qml/Wallet/ReceiveModal.qml | 2 +- atomic_qt_design/qml/Wallet/SendModal.qml | 2 +- atomic_qt_design/qml/Wallet/SendResult.qml | 2 +- atomic_qt_design/qml/Wallet/Sidebar.qml | 2 +- atomic_qt_design/qml/Wallet/TransactionDetailsModal.qml | 2 +- atomic_qt_design/qml/Wallet/Transactions.qml | 2 +- atomic_qt_design/qml/Wallet/Wallet.qml | 2 +- 95 files changed, 97 insertions(+), 95 deletions(-) diff --git a/atomic_qt_design/qml/Components/AddressField.qml b/atomic_qt_design/qml/Components/AddressField.qml index be7b279572..5194a8f81b 100644 --- a/atomic_qt_design/qml/Components/AddressField.qml +++ b/atomic_qt_design/qml/Components/AddressField.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/AddressFieldWithTitle.qml b/atomic_qt_design/qml/Components/AddressFieldWithTitle.qml index 6954b27c43..af90139ce9 100644 --- a/atomic_qt_design/qml/Components/AddressFieldWithTitle.qml +++ b/atomic_qt_design/qml/Components/AddressFieldWithTitle.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/AmountField.qml b/atomic_qt_design/qml/Components/AmountField.qml index 03209ac46e..da2b2b824a 100644 --- a/atomic_qt_design/qml/Components/AmountField.qml +++ b/atomic_qt_design/qml/Components/AmountField.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/AmountFieldWithInfo.qml b/atomic_qt_design/qml/Components/AmountFieldWithInfo.qml index e50cccb6b6..b178a8b47d 100644 --- a/atomic_qt_design/qml/Components/AmountFieldWithInfo.qml +++ b/atomic_qt_design/qml/Components/AmountFieldWithInfo.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/AmountIntField.qml b/atomic_qt_design/qml/Components/AmountIntField.qml index f10319409f..f072288b1d 100644 --- a/atomic_qt_design/qml/Components/AmountIntField.qml +++ b/atomic_qt_design/qml/Components/AmountIntField.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/Arrow.qml b/atomic_qt_design/qml/Components/Arrow.qml index d0a579185f..ec98bdd55e 100644 --- a/atomic_qt_design/qml/Components/Arrow.qml +++ b/atomic_qt_design/qml/Components/Arrow.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 import QtGraphicalEffects 1.0 diff --git a/atomic_qt_design/qml/Components/CexInfoTrigger.qml b/atomic_qt_design/qml/Components/CexInfoTrigger.qml index e630eb7cbc..d242cf7c15 100644 --- a/atomic_qt_design/qml/Components/CexInfoTrigger.qml +++ b/atomic_qt_design/qml/Components/CexInfoTrigger.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/Circle.qml b/atomic_qt_design/qml/Components/Circle.qml index af0836004d..1767b549c3 100644 --- a/atomic_qt_design/qml/Components/Circle.qml +++ b/atomic_qt_design/qml/Components/Circle.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 import QtGraphicalEffects 1.0 diff --git a/atomic_qt_design/qml/Components/ColumnHeader.qml b/atomic_qt_design/qml/Components/ColumnHeader.qml index 02922bc996..0290cb1da0 100644 --- a/atomic_qt_design/qml/Components/ColumnHeader.qml +++ b/atomic_qt_design/qml/Components/ColumnHeader.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/ComboBoxWithTitle.qml b/atomic_qt_design/qml/Components/ComboBoxWithTitle.qml index 0ec3f79b14..cfcf081a69 100644 --- a/atomic_qt_design/qml/Components/ComboBoxWithTitle.qml +++ b/atomic_qt_design/qml/Components/ComboBoxWithTitle.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/CopyFieldButton.qml b/atomic_qt_design/qml/Components/CopyFieldButton.qml index 9ed87aaa57..7ef98f4f7b 100644 --- a/atomic_qt_design/qml/Components/CopyFieldButton.qml +++ b/atomic_qt_design/qml/Components/CopyFieldButton.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/DangerButton.qml b/atomic_qt_design/qml/Components/DangerButton.qml index 8f9be34650..5eafb137b1 100644 --- a/atomic_qt_design/qml/Components/DangerButton.qml +++ b/atomic_qt_design/qml/Components/DangerButton.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/DefaultBusyIndicator.qml b/atomic_qt_design/qml/Components/DefaultBusyIndicator.qml index bf74ce482f..7f8c878f4c 100644 --- a/atomic_qt_design/qml/Components/DefaultBusyIndicator.qml +++ b/atomic_qt_design/qml/Components/DefaultBusyIndicator.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/DefaultButton.qml b/atomic_qt_design/qml/Components/DefaultButton.qml index 81bf4fe167..7f9bb97be5 100644 --- a/atomic_qt_design/qml/Components/DefaultButton.qml +++ b/atomic_qt_design/qml/Components/DefaultButton.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 import QtGraphicalEffects 1.0 diff --git a/atomic_qt_design/qml/Components/DefaultCheckBox.qml b/atomic_qt_design/qml/Components/DefaultCheckBox.qml index 6d356c0727..d2fd22e5d2 100644 --- a/atomic_qt_design/qml/Components/DefaultCheckBox.qml +++ b/atomic_qt_design/qml/Components/DefaultCheckBox.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 import QtQuick.Controls.Universal 2.12 diff --git a/atomic_qt_design/qml/Components/DefaultComboBox.qml b/atomic_qt_design/qml/Components/DefaultComboBox.qml index 888798b54d..e7ed87f97b 100644 --- a/atomic_qt_design/qml/Components/DefaultComboBox.qml +++ b/atomic_qt_design/qml/Components/DefaultComboBox.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 import QtQuick.Controls.Universal 2.12 diff --git a/atomic_qt_design/qml/Components/DefaultFlickable.qml b/atomic_qt_design/qml/Components/DefaultFlickable.qml index 12e1fd3d38..148dd53271 100644 --- a/atomic_qt_design/qml/Components/DefaultFlickable.qml +++ b/atomic_qt_design/qml/Components/DefaultFlickable.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/DefaultImage.qml b/atomic_qt_design/qml/Components/DefaultImage.qml index 9fedd8b4bf..1d3a04c662 100644 --- a/atomic_qt_design/qml/Components/DefaultImage.qml +++ b/atomic_qt_design/qml/Components/DefaultImage.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 import QtQuick.Controls.Universal 2.12 diff --git a/atomic_qt_design/qml/Components/DefaultInnerShadow.qml b/atomic_qt_design/qml/Components/DefaultInnerShadow.qml index f7c909a189..fa49c9521b 100644 --- a/atomic_qt_design/qml/Components/DefaultInnerShadow.qml +++ b/atomic_qt_design/qml/Components/DefaultInnerShadow.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/DefaultListView.qml b/atomic_qt_design/qml/Components/DefaultListView.qml index dbcc5fa2d2..36b9bba8d2 100644 --- a/atomic_qt_design/qml/Components/DefaultListView.qml +++ b/atomic_qt_design/qml/Components/DefaultListView.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/DefaultModal.qml b/atomic_qt_design/qml/Components/DefaultModal.qml index e53b2b572b..857213a1d8 100644 --- a/atomic_qt_design/qml/Components/DefaultModal.qml +++ b/atomic_qt_design/qml/Components/DefaultModal.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/DefaultRectangle.qml b/atomic_qt_design/qml/Components/DefaultRectangle.qml index 638ee14347..d632347625 100644 --- a/atomic_qt_design/qml/Components/DefaultRectangle.qml +++ b/atomic_qt_design/qml/Components/DefaultRectangle.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/DefaultScrollBar.qml b/atomic_qt_design/qml/Components/DefaultScrollBar.qml index a7eae0bb99..e80a4e4a3f 100644 --- a/atomic_qt_design/qml/Components/DefaultScrollBar.qml +++ b/atomic_qt_design/qml/Components/DefaultScrollBar.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/DefaultText.qml b/atomic_qt_design/qml/Components/DefaultText.qml index a19f6a31aa..34e941985f 100644 --- a/atomic_qt_design/qml/Components/DefaultText.qml +++ b/atomic_qt_design/qml/Components/DefaultText.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/DefaultTextArea.qml b/atomic_qt_design/qml/Components/DefaultTextArea.qml index 1100c3923c..56f4407d2a 100644 --- a/atomic_qt_design/qml/Components/DefaultTextArea.qml +++ b/atomic_qt_design/qml/Components/DefaultTextArea.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/DefaultTextField.qml b/atomic_qt_design/qml/Components/DefaultTextField.qml index c228e85c99..85a1ce3805 100644 --- a/atomic_qt_design/qml/Components/DefaultTextField.qml +++ b/atomic_qt_design/qml/Components/DefaultTextField.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/EulaModal.qml b/atomic_qt_design/qml/Components/EulaModal.qml index f0307c9f11..5751bb10a0 100644 --- a/atomic_qt_design/qml/Components/EulaModal.qml +++ b/atomic_qt_design/qml/Components/EulaModal.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/FloatingBackground.qml b/atomic_qt_design/qml/Components/FloatingBackground.qml index daf9b1f23b..c46c615711 100644 --- a/atomic_qt_design/qml/Components/FloatingBackground.qml +++ b/atomic_qt_design/qml/Components/FloatingBackground.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/GradientRectangle.qml b/atomic_qt_design/qml/Components/GradientRectangle.qml index 882ed7fae9..1b8f34036e 100644 --- a/atomic_qt_design/qml/Components/GradientRectangle.qml +++ b/atomic_qt_design/qml/Components/GradientRectangle.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/HideFieldButton.qml b/atomic_qt_design/qml/Components/HideFieldButton.qml index 5632641c43..3be23ef441 100644 --- a/atomic_qt_design/qml/Components/HideFieldButton.qml +++ b/atomic_qt_design/qml/Components/HideFieldButton.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/HorizontalLine.qml b/atomic_qt_design/qml/Components/HorizontalLine.qml index 67127c9013..788020eea2 100644 --- a/atomic_qt_design/qml/Components/HorizontalLine.qml +++ b/atomic_qt_design/qml/Components/HorizontalLine.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/InnerBackground.qml b/atomic_qt_design/qml/Components/InnerBackground.qml index 1ffcbb6be8..894d0612df 100644 --- a/atomic_qt_design/qml/Components/InnerBackground.qml +++ b/atomic_qt_design/qml/Components/InnerBackground.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 import QtGraphicalEffects 1.12 diff --git a/atomic_qt_design/qml/Components/LogModal.qml b/atomic_qt_design/qml/Components/LogModal.qml index 0c27c731af..718323b430 100644 --- a/atomic_qt_design/qml/Components/LogModal.qml +++ b/atomic_qt_design/qml/Components/LogModal.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/ModalHeader.qml b/atomic_qt_design/qml/Components/ModalHeader.qml index 10f34e4cc1..04d5c961b0 100644 --- a/atomic_qt_design/qml/Components/ModalHeader.qml +++ b/atomic_qt_design/qml/Components/ModalHeader.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/PasswordField.qml b/atomic_qt_design/qml/Components/PasswordField.qml index 42b7e0c920..374046133f 100644 --- a/atomic_qt_design/qml/Components/PasswordField.qml +++ b/atomic_qt_design/qml/Components/PasswordField.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/PasswordForm.qml b/atomic_qt_design/qml/Components/PasswordForm.qml index 0513f742f6..e715085b5e 100644 --- a/atomic_qt_design/qml/Components/PasswordForm.qml +++ b/atomic_qt_design/qml/Components/PasswordForm.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/PlusButton.qml b/atomic_qt_design/qml/Components/PlusButton.qml index f72529c29d..4e35a95d8e 100644 --- a/atomic_qt_design/qml/Components/PlusButton.qml +++ b/atomic_qt_design/qml/Components/PlusButton.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/PrimaryButton.qml b/atomic_qt_design/qml/Components/PrimaryButton.qml index 47fae4a3e6..4fbe00eb0f 100644 --- a/atomic_qt_design/qml/Components/PrimaryButton.qml +++ b/atomic_qt_design/qml/Components/PrimaryButton.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/RightClickMenu.qml b/atomic_qt_design/qml/Components/RightClickMenu.qml index 657523a6d4..44abb55fd8 100644 --- a/atomic_qt_design/qml/Components/RightClickMenu.qml +++ b/atomic_qt_design/qml/Components/RightClickMenu.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/Separator.qml b/atomic_qt_design/qml/Components/Separator.qml index 812ad1ea31..ff1cbb71df 100644 --- a/atomic_qt_design/qml/Components/Separator.qml +++ b/atomic_qt_design/qml/Components/Separator.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/SetupPage.qml b/atomic_qt_design/qml/Components/SetupPage.qml index c32615eb81..13716c8218 100644 --- a/atomic_qt_design/qml/Components/SetupPage.qml +++ b/atomic_qt_design/qml/Components/SetupPage.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/SidebarPanel.qml b/atomic_qt_design/qml/Components/SidebarPanel.qml index f17d743af9..8e013e7941 100644 --- a/atomic_qt_design/qml/Components/SidebarPanel.qml +++ b/atomic_qt_design/qml/Components/SidebarPanel.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/TextAreaWithTitle.qml b/atomic_qt_design/qml/Components/TextAreaWithTitle.qml index 6a9f33bf2a..4a1f36e335 100644 --- a/atomic_qt_design/qml/Components/TextAreaWithTitle.qml +++ b/atomic_qt_design/qml/Components/TextAreaWithTitle.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/TextFieldWithTitle.qml b/atomic_qt_design/qml/Components/TextFieldWithTitle.qml index 162dfd6d33..f8dc963239 100644 --- a/atomic_qt_design/qml/Components/TextFieldWithTitle.qml +++ b/atomic_qt_design/qml/Components/TextFieldWithTitle.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/TextWithTitle.qml b/atomic_qt_design/qml/Components/TextWithTitle.qml index bc0d4b94fc..c7834d8dff 100644 --- a/atomic_qt_design/qml/Components/TextWithTitle.qml +++ b/atomic_qt_design/qml/Components/TextWithTitle.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/Toast.qml b/atomic_qt_design/qml/Components/Toast.qml index a8f72888fb..50818862c5 100644 --- a/atomic_qt_design/qml/Components/Toast.qml +++ b/atomic_qt_design/qml/Components/Toast.qml @@ -1,7 +1,7 @@ // This is a modified version of QML Toast Implementation of jonmcclung // https://gist.github.com/jonmcclung/bae669101d17b103e94790341301c129 -import QtQuick 2.12 +import QtQuick 2.14 import "../Constants" Rectangle { diff --git a/atomic_qt_design/qml/Components/ToastManager.qml b/atomic_qt_design/qml/Components/ToastManager.qml index 5658086691..7821a80215 100644 --- a/atomic_qt_design/qml/Components/ToastManager.qml +++ b/atomic_qt_design/qml/Components/ToastManager.qml @@ -1,7 +1,7 @@ // This is a modified version of QML Toast Implementation of jonmcclung // https://gist.github.com/jonmcclung/bae669101d17b103e94790341301c129 -import QtQuick 2.12 +import QtQuick 2.14 ListView { function show(text, duration=-1, info="", is_error=true) { diff --git a/atomic_qt_design/qml/Components/UpdateModal.qml b/atomic_qt_design/qml/Components/UpdateModal.qml index a4e5610b46..d0cea24669 100644 --- a/atomic_qt_design/qml/Components/UpdateModal.qml +++ b/atomic_qt_design/qml/Components/UpdateModal.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/UpdateNotificationLine.qml b/atomic_qt_design/qml/Components/UpdateNotificationLine.qml index 8cf79aa5f9..15e744be22 100644 --- a/atomic_qt_design/qml/Components/UpdateNotificationLine.qml +++ b/atomic_qt_design/qml/Components/UpdateNotificationLine.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/VerticalLine.qml b/atomic_qt_design/qml/Components/VerticalLine.qml index 3f3f6939ac..a269aa49da 100644 --- a/atomic_qt_design/qml/Components/VerticalLine.qml +++ b/atomic_qt_design/qml/Components/VerticalLine.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/VerticalLineBasic.qml b/atomic_qt_design/qml/Components/VerticalLineBasic.qml index 47f3afde81..991f17de17 100644 --- a/atomic_qt_design/qml/Components/VerticalLineBasic.qml +++ b/atomic_qt_design/qml/Components/VerticalLineBasic.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Components/WalletNameField.qml b/atomic_qt_design/qml/Components/WalletNameField.qml index 56b60041cb..1cbe1b3b49 100644 --- a/atomic_qt_design/qml/Components/WalletNameField.qml +++ b/atomic_qt_design/qml/Components/WalletNameField.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Exchange/Exchange.qml b/atomic_qt_design/qml/Exchange/Exchange.qml index 3f4fe8cfa0..79c2af7fc3 100644 --- a/atomic_qt_design/qml/Exchange/Exchange.qml +++ b/atomic_qt_design/qml/Exchange/Exchange.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Exchange/ExchangeTab.qml b/atomic_qt_design/qml/Exchange/ExchangeTab.qml index a81ed16416..e12e1149be 100644 --- a/atomic_qt_design/qml/Exchange/ExchangeTab.qml +++ b/atomic_qt_design/qml/Exchange/ExchangeTab.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Exchange/History/History.qml b/atomic_qt_design/qml/Exchange/History/History.qml index a71b7f92b9..59d837b04b 100644 --- a/atomic_qt_design/qml/Exchange/History/History.qml +++ b/atomic_qt_design/qml/Exchange/History/History.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Exchange/History/SwapList.qml b/atomic_qt_design/qml/Exchange/History/SwapList.qml index e5bbfe474f..cdd7cc7b3b 100644 --- a/atomic_qt_design/qml/Exchange/History/SwapList.qml +++ b/atomic_qt_design/qml/Exchange/History/SwapList.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Exchange/OrderContent.qml b/atomic_qt_design/qml/Exchange/OrderContent.qml index 92249def45..2c05524f93 100644 --- a/atomic_qt_design/qml/Exchange/OrderContent.qml +++ b/atomic_qt_design/qml/Exchange/OrderContent.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Exchange/OrderLine.qml b/atomic_qt_design/qml/Exchange/OrderLine.qml index d4d95779b5..cece48305b 100644 --- a/atomic_qt_design/qml/Exchange/OrderLine.qml +++ b/atomic_qt_design/qml/Exchange/OrderLine.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Exchange/OrderModal.qml b/atomic_qt_design/qml/Exchange/OrderModal.qml index 5647b1af72..b5f5d2738c 100644 --- a/atomic_qt_design/qml/Exchange/OrderModal.qml +++ b/atomic_qt_design/qml/Exchange/OrderModal.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Exchange/Orders/OrderList.qml b/atomic_qt_design/qml/Exchange/Orders/OrderList.qml index f4c3914801..730314b4fd 100644 --- a/atomic_qt_design/qml/Exchange/Orders/OrderList.qml +++ b/atomic_qt_design/qml/Exchange/Orders/OrderList.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Exchange/Orders/Orders.qml b/atomic_qt_design/qml/Exchange/Orders/Orders.qml index 06b4c24421..73a4cf6fef 100644 --- a/atomic_qt_design/qml/Exchange/Orders/Orders.qml +++ b/atomic_qt_design/qml/Exchange/Orders/Orders.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index 76983cb07f..39a1903c57 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 import QtGraphicalEffects 1.0 diff --git a/atomic_qt_design/qml/Exchange/Trade/Orderbook.qml b/atomic_qt_design/qml/Exchange/Trade/Orderbook.qml index 7ef96314d4..a9b60b9b9c 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Orderbook.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Orderbook.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml index 0e80f1f40f..f8cd9dcf56 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderbookSection.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Exchange/Trade/PriceLine.qml b/atomic_qt_design/qml/Exchange/Trade/PriceLine.qml index e9d6231710..a376287c6a 100644 --- a/atomic_qt_design/qml/Exchange/Trade/PriceLine.qml +++ b/atomic_qt_design/qml/Exchange/Trade/PriceLine.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml b/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml index 21e0792897..8bfcff8bd3 100644 --- a/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml +++ b/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.14 import QtGraphicalEffects 1.0 diff --git a/atomic_qt_design/qml/NoConnection.qml b/atomic_qt_design/qml/NoConnection.qml index a4cb6c9127..65574be88f 100644 --- a/atomic_qt_design/qml/NoConnection.qml +++ b/atomic_qt_design/qml/NoConnection.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Portfolio/Portfolio.qml b/atomic_qt_design/qml/Portfolio/Portfolio.qml index 8f84075bbe..64c4ddeaa0 100644 --- a/atomic_qt_design/qml/Portfolio/Portfolio.qml +++ b/atomic_qt_design/qml/Portfolio/Portfolio.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Screens/Dashboard.qml b/atomic_qt_design/qml/Screens/Dashboard.qml index 42d9d03d10..0b20cd84ae 100644 --- a/atomic_qt_design/qml/Screens/Dashboard.qml +++ b/atomic_qt_design/qml/Screens/Dashboard.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Screens/FirstLaunch.qml b/atomic_qt_design/qml/Screens/FirstLaunch.qml index e07888fa9c..5cf3db7e4d 100644 --- a/atomic_qt_design/qml/Screens/FirstLaunch.qml +++ b/atomic_qt_design/qml/Screens/FirstLaunch.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Screens/InitialLoading.qml b/atomic_qt_design/qml/Screens/InitialLoading.qml index e0901fc0f0..e9c9fb9db4 100644 --- a/atomic_qt_design/qml/Screens/InitialLoading.qml +++ b/atomic_qt_design/qml/Screens/InitialLoading.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Screens/Login.qml b/atomic_qt_design/qml/Screens/Login.qml index 8d634da99c..6c6e6dbac9 100644 --- a/atomic_qt_design/qml/Screens/Login.qml +++ b/atomic_qt_design/qml/Screens/Login.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Screens/NewUser.qml b/atomic_qt_design/qml/Screens/NewUser.qml index 853a11c187..e94033b595 100644 --- a/atomic_qt_design/qml/Screens/NewUser.qml +++ b/atomic_qt_design/qml/Screens/NewUser.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Screens/RecoverSeed.qml b/atomic_qt_design/qml/Screens/RecoverSeed.qml index f87723af25..07d2233a86 100644 --- a/atomic_qt_design/qml/Screens/RecoverSeed.qml +++ b/atomic_qt_design/qml/Screens/RecoverSeed.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Settings/DeleteWalletModal.qml b/atomic_qt_design/qml/Settings/DeleteWalletModal.qml index 2fc15859b9..abdef250bc 100644 --- a/atomic_qt_design/qml/Settings/DeleteWalletModal.qml +++ b/atomic_qt_design/qml/Settings/DeleteWalletModal.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Settings/Languages.qml b/atomic_qt_design/qml/Settings/Languages.qml index 7647e0bfec..3aded49e69 100644 --- a/atomic_qt_design/qml/Settings/Languages.qml +++ b/atomic_qt_design/qml/Settings/Languages.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Settings/RecoverSeedModal.qml b/atomic_qt_design/qml/Settings/RecoverSeedModal.qml index 6409584e09..6df90a4cff 100644 --- a/atomic_qt_design/qml/Settings/RecoverSeedModal.qml +++ b/atomic_qt_design/qml/Settings/RecoverSeedModal.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Settings/Settings.qml b/atomic_qt_design/qml/Settings/Settings.qml index b865b62096..5182ae34c3 100644 --- a/atomic_qt_design/qml/Settings/Settings.qml +++ b/atomic_qt_design/qml/Settings/Settings.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Sidebar/Sidebar.qml b/atomic_qt_design/qml/Sidebar/Sidebar.qml index d8196587a8..064d81186d 100644 --- a/atomic_qt_design/qml/Sidebar/Sidebar.qml +++ b/atomic_qt_design/qml/Sidebar/Sidebar.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Sidebar/SidebarBottom.qml b/atomic_qt_design/qml/Sidebar/SidebarBottom.qml index 9e12d7f714..03665c4dfd 100644 --- a/atomic_qt_design/qml/Sidebar/SidebarBottom.qml +++ b/atomic_qt_design/qml/Sidebar/SidebarBottom.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Sidebar/SidebarCenter.qml b/atomic_qt_design/qml/Sidebar/SidebarCenter.qml index cf9f44a7c6..d3b037ee7a 100644 --- a/atomic_qt_design/qml/Sidebar/SidebarCenter.qml +++ b/atomic_qt_design/qml/Sidebar/SidebarCenter.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Sidebar/SidebarLine.qml b/atomic_qt_design/qml/Sidebar/SidebarLine.qml index 7d8f626c1c..99383e78d8 100644 --- a/atomic_qt_design/qml/Sidebar/SidebarLine.qml +++ b/atomic_qt_design/qml/Sidebar/SidebarLine.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Wallet/AddressBook.qml b/atomic_qt_design/qml/Wallet/AddressBook.qml index db71b3b6c5..4effc2fc07 100644 --- a/atomic_qt_design/qml/Wallet/AddressBook.qml +++ b/atomic_qt_design/qml/Wallet/AddressBook.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Wallet/AddressList.qml b/atomic_qt_design/qml/Wallet/AddressList.qml index 3228be5814..1c26866418 100644 --- a/atomic_qt_design/qml/Wallet/AddressList.qml +++ b/atomic_qt_design/qml/Wallet/AddressList.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml index d811d9046c..7d004d84bb 100644 --- a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml +++ b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 @@ -104,6 +104,8 @@ DefaultModal { visible: text !== '' } + + // Buttons RowLayout { DefaultButton { diff --git a/atomic_qt_design/qml/Wallet/CoinList.qml b/atomic_qt_design/qml/Wallet/CoinList.qml index 4c60a3398b..42c4c24773 100644 --- a/atomic_qt_design/qml/Wallet/CoinList.qml +++ b/atomic_qt_design/qml/Wallet/CoinList.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Wallet/EnableCoinModal.qml b/atomic_qt_design/qml/Wallet/EnableCoinModal.qml index 10b0765c99..c9696fdcc9 100644 --- a/atomic_qt_design/qml/Wallet/EnableCoinModal.qml +++ b/atomic_qt_design/qml/Wallet/EnableCoinModal.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Wallet/PriceGraph.qml b/atomic_qt_design/qml/Wallet/PriceGraph.qml index 551cf3f953..6abb0144f2 100644 --- a/atomic_qt_design/qml/Wallet/PriceGraph.qml +++ b/atomic_qt_design/qml/Wallet/PriceGraph.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Wallet/ReceiveModal.qml b/atomic_qt_design/qml/Wallet/ReceiveModal.qml index 236b97385a..e24d93a42c 100644 --- a/atomic_qt_design/qml/Wallet/ReceiveModal.qml +++ b/atomic_qt_design/qml/Wallet/ReceiveModal.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Wallet/SendModal.qml b/atomic_qt_design/qml/Wallet/SendModal.qml index a5a5ffd8db..e26b64a2d9 100644 --- a/atomic_qt_design/qml/Wallet/SendModal.qml +++ b/atomic_qt_design/qml/Wallet/SendModal.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Wallet/SendResult.qml b/atomic_qt_design/qml/Wallet/SendResult.qml index bfdaad4e74..3a58cb90ee 100644 --- a/atomic_qt_design/qml/Wallet/SendResult.qml +++ b/atomic_qt_design/qml/Wallet/SendResult.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Wallet/Sidebar.qml b/atomic_qt_design/qml/Wallet/Sidebar.qml index 97aeb8eccf..0771d43a93 100644 --- a/atomic_qt_design/qml/Wallet/Sidebar.qml +++ b/atomic_qt_design/qml/Wallet/Sidebar.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Wallet/TransactionDetailsModal.qml b/atomic_qt_design/qml/Wallet/TransactionDetailsModal.qml index f46b441ea4..d45e2c9265 100644 --- a/atomic_qt_design/qml/Wallet/TransactionDetailsModal.qml +++ b/atomic_qt_design/qml/Wallet/TransactionDetailsModal.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Wallet/Transactions.qml b/atomic_qt_design/qml/Wallet/Transactions.qml index ed2bba3a45..c9e0c45956 100644 --- a/atomic_qt_design/qml/Wallet/Transactions.qml +++ b/atomic_qt_design/qml/Wallet/Transactions.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Wallet/Wallet.qml b/atomic_qt_design/qml/Wallet/Wallet.qml index 66013c1cfd..25c3665663 100644 --- a/atomic_qt_design/qml/Wallet/Wallet.qml +++ b/atomic_qt_design/qml/Wallet/Wallet.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 From 6121e709265af7ac27c24eb53be8351e597041e9 Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 11 Aug 2020 20:25:37 +0300 Subject: [PATCH 267/515] feat(gui): upgrade qtquick 2.12 to 2.14 --- atomic_qt_design/qml/App.qml | 2 +- atomic_qt_design/qml/Dashboard/NotificationsPanel.qml | 2 +- atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml | 2 +- atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml | 2 +- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 2 +- atomic_qt_design/qml/Wallet/Main.qml | 2 +- atomic_qt_design/qml/main.qml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/atomic_qt_design/qml/App.qml b/atomic_qt_design/qml/App.qml index 023c1396be..1c040c63f3 100644 --- a/atomic_qt_design/qml/App.qml +++ b/atomic_qt_design/qml/App.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml index 118cd33462..226554c2d1 100644 --- a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml +++ b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 import Qt.labs.platform 1.0 diff --git a/atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml b/atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml index 3420497c5c..fbaff96021 100644 --- a/atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml +++ b/atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml index d8d24f9957..7870b8f410 100644 --- a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml +++ b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index f67c790fa7..7a07273cbb 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/Wallet/Main.qml b/atomic_qt_design/qml/Wallet/Main.qml index 455bcd0317..1f34c232b2 100644 --- a/atomic_qt_design/qml/Wallet/Main.qml +++ b/atomic_qt_design/qml/Wallet/Main.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 diff --git a/atomic_qt_design/qml/main.qml b/atomic_qt_design/qml/main.qml index 2fee9174b9..c3fd777821 100644 --- a/atomic_qt_design/qml/main.qml +++ b/atomic_qt_design/qml/main.qml @@ -1,4 +1,4 @@ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Window 2.12 import "Screens" import "Constants" From 5dcbfd938cb526d3d47068532aa33bef0965b9b7 Mon Sep 17 00:00:00 2001 From: milerius Date: Tue, 11 Aug 2020 20:21:53 +0200 Subject: [PATCH 268/515] feat(rewards): add start_at --- src/atomic.dex.mm2.api.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/atomic.dex.mm2.api.cpp b/src/atomic.dex.mm2.api.cpp index 10e0459401..95e15f1df0 100644 --- a/src/atomic.dex.mm2.api.cpp +++ b/src/atomic.dex.mm2.api.cpp @@ -1118,6 +1118,12 @@ namespace mm2::api { for (auto&& obj: out.result.at("result")) { + if (obj.contains("accrue_start_at")) + { + std::size_t accrue_timestamp = obj.at("accrue_start_at").get(); + obj["accrue_start_at_human_date"] = to_human_date(accrue_timestamp, "%e %b %Y, %I:%M"); + } + if (obj.contains("accrue_stop_at")) { std::size_t accrue_timestamp = obj.at("accrue_stop_at").get(); From 5e57a91c67f4cbdfff59738d606ec4aa83fc2b4a Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 11 Aug 2020 22:40:29 +0300 Subject: [PATCH 269/515] feat(gui): add verbose claim rewards info table --- atomic_qt_design/qml/Constants/General.qml | 17 ++ .../qml/Wallet/ClaimRewardsModal.qml | 249 +++++++++++++++++- 2 files changed, 263 insertions(+), 3 deletions(-) diff --git a/atomic_qt_design/qml/Constants/General.qml b/atomic_qt_design/qml/Constants/General.qml index 2020fff5af..f35cb8406c 100644 --- a/atomic_qt_design/qml/Constants/General.qml +++ b/atomic_qt_design/qml/Constants/General.qml @@ -61,6 +61,23 @@ QtObject { function timestampToDate(timestamp) { return (new Date(timestamp * 1000)) } + + function secondsToTimeLeft(date_now, date_future) { + let delta = Math.abs(date_future - date_now) + + let days = Math.floor(delta / 86400) + delta -= days * 86400 + + let hours = Math.floor(delta / 3600) % 24 + delta -= hours * 3600 + + let minutes = Math.floor(delta / 60) % 60 + delta -= minutes * 60 + + let seconds = Math.floor(delta) % 60 // in theory the modulus is not required + + return days + ':' + hours + ':' + minutes + ':' + seconds + } function clone(obj) { return JSON.parse(JSON.stringify(obj)); diff --git a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml index 7d004d84bb..3a214414e1 100644 --- a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml +++ b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml @@ -80,7 +80,7 @@ DefaultModal { // Inside modal // width: stack_layout.children[stack_layout.currentIndex].width + horizontalPadding * 2 - width: 650 + width: 1000 height: stack_layout.children[stack_layout.currentIndex].height + verticalPadding * 2 StackLayout { width: parent.width @@ -88,6 +88,7 @@ DefaultModal { ColumnLayout { Layout.fillWidth: true + Layout.alignment: Qt.AlignHCenter ModalHeader { title: API.get().settings_pg.empty_string + (qsTr("Claim your %1 reward?", "TICKER").arg(API.get().current_coin_info.ticker)) @@ -98,14 +99,256 @@ DefaultModal { text_value: API.get().settings_pg.empty_string + (qsTr("You will receive %1", "AMT TICKER").arg(General.formatCrypto("", prepare_claim_rewards_result.withdraw_answer.my_balance_change, API.get().current_coin_info.ticker))) } + // List header + Item { + Layout.topMargin: 30 + Layout.fillWidth: true + + height: 40 + + // Price + DefaultText { + id: utxo_header + font.pixelSize: Style.textSizeSmall2 + + text_value: API.get().settings_pg.empty_string + (qsTr("UTXO")) + + font.bold: true + horizontalAlignment: Text.AlignLeft + + anchors.left: parent.left + anchors.leftMargin: parent.width * 0.03 + + anchors.verticalCenter: parent.verticalCenter + } + + // Amount + DefaultText { + id: amount_header + + text_value: API.get().settings_pg.empty_string + (qsTr("Amount")) + + font.pixelSize: utxo_header.font.pixelSize + font.bold: utxo_header.font.bold + horizontalAlignment: utxo_header.horizontalAlignment + + anchors.left: parent.left + anchors.leftMargin: parent.width * 0.075 + + anchors.verticalCenter: parent.verticalCenter + } + + // Reward + DefaultText { + id: reward_header + + text_value: API.get().settings_pg.empty_string + (qsTr("Reward")) + + font.pixelSize: utxo_header.font.pixelSize + font.bold: utxo_header.font.bold + horizontalAlignment: Text.AlignLeft + + anchors.left: parent.left + anchors.leftMargin: parent.width * 0.2 + + anchors.verticalCenter: parent.verticalCenter + } + + // Accruing start + DefaultText { + id: accruing_start_header + + text_value: API.get().settings_pg.empty_string + (qsTr("Accruing Start At")) + + font.pixelSize: utxo_header.font.pixelSize + font.bold: utxo_header.font.bold + horizontalAlignment: Text.AlignLeft + + anchors.left: parent.left + anchors.leftMargin: parent.width * 0.325 + + anchors.verticalCenter: parent.verticalCenter + } + + // Accruing Stop + DefaultText { + id: accruing_stop_header + + text_value: API.get().settings_pg.empty_string + (qsTr("Accruing Stop At")) + + font.pixelSize: utxo_header.font.pixelSize + font.bold: utxo_header.font.bold + horizontalAlignment: Text.AlignLeft + + anchors.left: parent.left + anchors.leftMargin: parent.width * 0.475 + + anchors.verticalCenter: parent.verticalCenter + } + + // Time Left + DefaultText { + id: time_left_header + + text_value: API.get().settings_pg.empty_string + (qsTr("Time Left (d:hh:mm:ss)")) + + font.pixelSize: utxo_header.font.pixelSize + font.bold: utxo_header.font.bold + horizontalAlignment: Text.AlignLeft + + anchors.left: parent.left + anchors.leftMargin: parent.width * 0.625 + + anchors.verticalCenter: parent.verticalCenter + } + + // Error + DefaultText { + id: error_header + + text_value: API.get().settings_pg.empty_string + (qsTr("Error")) + + font.pixelSize: utxo_header.font.pixelSize + font.bold: utxo_header.font.bold + horizontalAlignment: Text.AlignLeft + + anchors.left: parent.left + anchors.leftMargin: parent.width * 0.8 + + anchors.verticalCenter: parent.verticalCenter + } + + // Line + HorizontalLine { + width: parent.width + color: Style.colorWhite5 + anchors.bottom: parent.bottom + } + } + + DefaultListView { + id: list + Layout.fillWidth: true + Layout.fillHeight: true + Layout.maximumHeight: 500 + clip: true + + model: prepare_claim_rewards_result.kmd_rewards_info.result + + delegate: Item { + width: root.width + height: utxo_value.font.pixelSize * 1.5 + + // UTXO + DefaultText { + id: utxo_value + + anchors.left: parent.left + anchors.leftMargin: utxo_header.anchors.leftMargin + + font.pixelSize: Style.textSizeSmall1 + + text_value: API.get().settings_pg.empty_string + ("#" + modelData.output_index) + anchors.verticalCenter: parent.verticalCenter + } + + // Amount + DefaultText { + id: amount_value + + anchors.left: parent.left + anchors.leftMargin: amount_header.anchors.leftMargin + + font.pixelSize: utxo_value.font.pixelSize + + text_value: API.get().settings_pg.empty_string + (modelData.amount) + anchors.verticalCenter: parent.verticalCenter + } + + // Reward + DefaultText { + id: reward_value + + anchors.left: parent.left + anchors.leftMargin: reward_header.anchors.leftMargin + + font.pixelSize: utxo_value.font.pixelSize + + text_value: API.get().settings_pg.empty_string + (modelData.accrued_rewards.Accrued || "-") + anchors.verticalCenter: parent.verticalCenter + } + + // Accruing Start + DefaultText { + id: accruing_start_value + + anchors.left: parent.left + anchors.leftMargin: accruing_start_header.anchors.leftMargin + + font.pixelSize: utxo_value.font.pixelSize + + text_value: API.get().settings_pg.empty_string + (modelData.accrue_start_at_human_date) + anchors.verticalCenter: parent.verticalCenter + } + + // Accruing Stop + DefaultText { + id: accruing_stop_value + + anchors.left: parent.left + anchors.leftMargin: accruing_stop_header.anchors.leftMargin + + font.pixelSize: utxo_value.font.pixelSize + + text_value: API.get().settings_pg.empty_string + (modelData.accrue_stop_at_human_date) + anchors.verticalCenter: parent.verticalCenter + } + + // Time Left + DefaultText { + id: time_left_value + + anchors.left: parent.left + anchors.leftMargin: time_left_header.anchors.leftMargin + + font.pixelSize: utxo_value.font.pixelSize + + text_value: API.get().settings_pg.empty_string + (General.secondsToTimeLeft(Date.now()/1000, modelData.accrue_stop_at)) + anchors.verticalCenter: parent.verticalCenter + } + + // Error + DefaultText { + id: error_value + + anchors.left: parent.left + anchors.leftMargin: error_header.anchors.leftMargin + + font.pixelSize: utxo_value.font.pixelSize + + text_value: { + return API.get().settings_pg.empty_string + (modelData.accrued_rewards.NotAccruedReason || "-") + } + anchors.verticalCenter: parent.verticalCenter + } + + // Line + HorizontalLine { + visible: prepare_claim_rewards_result.kmd_rewards_info.result && + index !== prepare_claim_rewards_result.kmd_rewards_info.result.length - 1 + width: parent.width + color: Style.colorWhite9 + anchors.bottom: parent.bottom + } + } + } + DefaultText { id: text_error color: Style.colorRed visible: text !== '' } - - // Buttons RowLayout { DefaultButton { From c7d441575fe51a5015afa56442d08d11541da2ef Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 11 Aug 2020 22:50:37 +0300 Subject: [PATCH 270/515] feat(gui): disable claim button if my_balance_change <= 0 --- atomic_qt_design/qml/Constants/General.qml | 5 ++++- atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml | 9 ++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/Constants/General.qml b/atomic_qt_design/qml/Constants/General.qml index f35cb8406c..a2fc5d1b0a 100644 --- a/atomic_qt_design/qml/Constants/General.qml +++ b/atomic_qt_design/qml/Constants/General.qml @@ -70,11 +70,14 @@ QtObject { let hours = Math.floor(delta / 3600) % 24 delta -= hours * 3600 + if(hours < 10) hours = '0' + hours let minutes = Math.floor(delta / 60) % 60 delta -= minutes * 60 + if(minutes < 10) minutes = '0' + minutes - let seconds = Math.floor(delta) % 60 // in theory the modulus is not required + let seconds = Math.floor(delta) % 60 + if(seconds < 10) seconds = '0' + seconds return days + ':' + hours + ':' + minutes + ':' + seconds } diff --git a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml index 3a214414e1..1b15c7f932 100644 --- a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml +++ b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml @@ -8,6 +8,8 @@ import "../Constants" DefaultModal { id: root + readonly property bool positive_claim_amount: parseFloat(prepare_claim_rewards_result.withdraw_answer.my_balance_change) > 0 + readonly property var default_prepare_claim_rewards_result: ({ "kmd_rewards_info": { "result": [ @@ -96,7 +98,11 @@ DefaultModal { DefaultText { visible: text_error.text === "" - text_value: API.get().settings_pg.empty_string + (qsTr("You will receive %1", "AMT TICKER").arg(General.formatCrypto("", prepare_claim_rewards_result.withdraw_answer.my_balance_change, API.get().current_coin_info.ticker))) + color: positive_claim_amount ? Style.colorText : Style.colorRed + text_value: API.get().settings_pg.empty_string + + (positive_claim_amount ? + qsTr("You will receive %1", "AMT TICKER").arg(General.formatCrypto("", prepare_claim_rewards_result.withdraw_answer.my_balance_change, API.get().current_coin_info.ticker)) + : qsTr("Transaction fee is higher than the reward!")) } // List header @@ -360,6 +366,7 @@ DefaultModal { text: API.get().settings_pg.empty_string + (qsTr("Confirm")) Layout.fillWidth: true onClicked: claimRewards() + enabled: positive_claim_amount } } } From a0de56ace6d55e7a1b9a65b8e1b69b18398a2bc1 Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 11 Aug 2020 23:00:31 +0300 Subject: [PATCH 271/515] feat(gui): adjust positioning, add error descriptions --- .../qml/Wallet/ClaimRewardsModal.qml | 42 +++++++++++++++---- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml index 1b15c7f932..cd62326378 100644 --- a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml +++ b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml @@ -82,7 +82,7 @@ DefaultModal { // Inside modal // width: stack_layout.children[stack_layout.currentIndex].width + horizontalPadding * 2 - width: 1000 + width: 1200 height: stack_layout.children[stack_layout.currentIndex].height + verticalPadding * 2 StackLayout { width: parent.width @@ -155,7 +155,7 @@ DefaultModal { horizontalAlignment: Text.AlignLeft anchors.left: parent.left - anchors.leftMargin: parent.width * 0.2 + anchors.leftMargin: parent.width * 0.175 anchors.verticalCenter: parent.verticalCenter } @@ -171,7 +171,7 @@ DefaultModal { horizontalAlignment: Text.AlignLeft anchors.left: parent.left - anchors.leftMargin: parent.width * 0.325 + anchors.leftMargin: parent.width * 0.300 anchors.verticalCenter: parent.verticalCenter } @@ -187,7 +187,7 @@ DefaultModal { horizontalAlignment: Text.AlignLeft anchors.left: parent.left - anchors.leftMargin: parent.width * 0.475 + anchors.leftMargin: parent.width * 0.450 anchors.verticalCenter: parent.verticalCenter } @@ -203,7 +203,7 @@ DefaultModal { horizontalAlignment: Text.AlignLeft anchors.left: parent.left - anchors.leftMargin: parent.width * 0.625 + anchors.leftMargin: parent.width * 0.600 anchors.verticalCenter: parent.verticalCenter } @@ -219,7 +219,7 @@ DefaultModal { horizontalAlignment: Text.AlignLeft anchors.left: parent.left - anchors.leftMargin: parent.width * 0.8 + anchors.leftMargin: parent.width * 0.750 anchors.verticalCenter: parent.verticalCenter } @@ -333,8 +333,36 @@ DefaultModal { font.pixelSize: utxo_value.font.pixelSize text_value: { - return API.get().settings_pg.empty_string + (modelData.accrued_rewards.NotAccruedReason || "-") + let val = modelData.accrued_rewards.NotAccruedReason + if(val === null || modelData.accrued_rewards.NotAccruedReason === undefined) return "-" + + switch(modelData.accrued_rewards.NotAccruedReason) { + case "LocktimeNotSet": + val = qsTr("Locktime is not set") + break + case "LocktimeLessThanThreshold": + val = qsTr("Locktime is less than the threshold") + break + case "UtxoHeightGreaterThanEndOfEra": + val = qsTr("UTXO height is greater than end of the era") + break + case "UtxoAmountLessThanTen": + val = qsTr("UTXO amount is less than 10") + break + case "OneHourNotPassedYet": + val = qsTr("One hour did not pass yet") + break + case "TransactionInMempool": + val = qsTr("Transaction is in mempool") + break + default: + val = qsTr("Unknown problem") + break + } + + return API.get().settings_pg.empty_string + (val) } + anchors.verticalCenter: parent.verticalCenter } From 612419b814105e61b3c47cc641f46394b3f52011 Mon Sep 17 00:00:00 2001 From: milerius Date: Tue, 11 Aug 2020 22:11:09 +0200 Subject: [PATCH 272/515] feat(rewards): add date --- src/atomic.dex.mm2.api.cpp | 9 +++++---- src/atomic.dex.mm2.cpp | 7 ++++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/atomic.dex.mm2.api.cpp b/src/atomic.dex.mm2.api.cpp index 95e15f1df0..5b0c0daca9 100644 --- a/src/atomic.dex.mm2.api.cpp +++ b/src/atomic.dex.mm2.api.cpp @@ -1120,19 +1120,20 @@ namespace mm2::api { if (obj.contains("accrue_start_at")) { - std::size_t accrue_timestamp = obj.at("accrue_start_at").get(); + auto accrue_timestamp = obj.at("accrue_start_at").get(); obj["accrue_start_at_human_date"] = to_human_date(accrue_timestamp, "%e %b %Y, %I:%M"); } if (obj.contains("accrue_stop_at")) { - std::size_t accrue_timestamp = obj.at("accrue_stop_at").get(); + auto accrue_timestamp = obj.at("accrue_stop_at").get(); obj["accrue_stop_at_human_date"] = to_human_date(accrue_timestamp, "%e %b %Y, %I:%M"); } + if (obj.contains("locktime")) { - std::size_t locktime_timestamp = obj.at("locktime").get(); - obj["locktime_human_date"] = to_human_date(locktime_timestamp, "%e %b %Y, %I:%M"); + auto locktime_timestamp = obj.at("locktime").get(); + obj["locktime_human_date"] = to_human_date(locktime_timestamp, "%e %b %Y, %I:%M"); } } } diff --git a/src/atomic.dex.mm2.cpp b/src/atomic.dex.mm2.cpp index 670a289972..905856c0ab 100644 --- a/src/atomic.dex.mm2.cpp +++ b/src/atomic.dex.mm2.cpp @@ -1051,7 +1051,7 @@ namespace atomic_dex { spdlog::debug("{} l{} f[{}]", __FUNCTION__, __LINE__, fs::path(__FILE__).filename().string()); - nlohmann::json out = nlohmann::json::object(); + nlohmann::json out = nlohmann::json::object(); const auto& info = get_coin_info(ticker); if (not info.is_claimable || not do_i_have_enough_funds(ticker, t_float_50(info.minimal_claim_amount))) { @@ -1062,8 +1062,9 @@ namespace atomic_dex auto answer = ::mm2::api::rpc_withdraw(std::move(req)); if (answer.rpc_result_code == 200) { - out["withdraw_answer"] = nlohmann::json::parse(answer.raw_result); - out["kmd_rewards_info"] = ::mm2::api::rpc_kmd_rewards_info().result; + out["withdraw_answer"] = nlohmann::json::parse(answer.raw_result); + out.at("withdraw_answer")["date"] = answer.result.value().timestamp_as_date; + out["kmd_rewards_info"] = ::mm2::api::rpc_kmd_rewards_info().result; } return out; } From 2544d50b2b194af129a3170e8b9b0982651a99d8 Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 11 Aug 2020 23:15:51 +0300 Subject: [PATCH 273/515] feat(gui): new values for claim rewards result page --- atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml index cd62326378..69a4e6360c 100644 --- a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml +++ b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml @@ -401,7 +401,11 @@ DefaultModal { // Result Page SendResult { - result: prepare_claim_rewards_result + result: ({ + balance_change: prepare_claim_rewards_result.withdraw_answer.my_balance_change, + fees: prepare_claim_rewards_result.withdraw_answer.fee_details.amount, + date: prepare_claim_rewards_result.withdraw_answer.date + }) tx_hash: send_result function onClose() { root.close() } From 8125aa538ea78b61cbc2581fbe6d2b118d363592 Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 11 Aug 2020 23:17:25 +0300 Subject: [PATCH 274/515] feat(gui): code polish --- atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml index 69a4e6360c..3ef17dfa59 100644 --- a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml +++ b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml @@ -334,9 +334,9 @@ DefaultModal { text_value: { let val = modelData.accrued_rewards.NotAccruedReason - if(val === null || modelData.accrued_rewards.NotAccruedReason === undefined) return "-" + if(val === null || val === undefined) return "-" - switch(modelData.accrued_rewards.NotAccruedReason) { + switch(val) { case "LocktimeNotSet": val = qsTr("Locktime is not set") break From cf2d429f8dc83d3453cf6eac160830f39dc03037 Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 11 Aug 2020 23:52:36 +0300 Subject: [PATCH 275/515] feat(gui): add refresh button --- .../qml/Wallet/ClaimRewardsModal.qml | 36 +++++++++---------- atomic_qt_design/qml/Wallet/Main.qml | 4 +-- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml index 3ef17dfa59..a67ee87861 100644 --- a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml +++ b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml @@ -16,12 +16,12 @@ DefaultModal { { "accrue_start_at": 1596785618, "accrue_stop_at": 1599460418, - "accrue_start_at_human_date": " 7 Aug 2020, 08:33", - "accrue_stop_at_human_date": " 7 Sep 2020, 08:33", + "accrue_start_at_human_date": "7 Aug 2020, 08:33", + "accrue_stop_at_human_date": "7 Sep 2020, 08:33", "accrued_rewards": { - "Accrued": "0.04973265" + "Accrued": "0" }, - "amount": "103.62356229", + "amount": "0", "output_index": 0 } ] @@ -30,9 +30,10 @@ DefaultModal { "fee_details": { "amount": "0.00001" }, - "my_balance_change": "0.04972265", - "tx_hash": "45f7a75e9782998f3a0809ea9ec8b68d3bdc438d34b6fc4114a6c8eddc3be6ae", - "tx_hex": "0400008085202f8901bc8f81d43c4133f5ffe68d5f07c6dcf785d34b2bb184f91bdb6e990bd8ab0977000000006a473044022014b3f1dbca1e28c5958f94cf5d1aa97b3d49f53d2409baefb2cc882f3883eb3a02200d26f5deafdb6e0475d4b50764e1c77a69872413e75576beeba993a1d63225f3012102d4acb3b1cc944b8b44836c6a4ef87bdee906ce268465bde8106cfee171b7f40dffffffff01eee0f069020000001976a914eed5d3ad264ffc68fc0a6454e1696a30d8f405be88ac1aa3315f000000000000000000000000000000" + "date": "7 Aug 2020, 08:33", + "my_balance_change": "0", + "tx_hash": "", + "tx_hex": "" } }) property var prepare_claim_rewards_result: default_prepare_claim_rewards_result @@ -62,10 +63,8 @@ DefaultModal { toast.show(qsTr("Failed to get the rewards info"), General.time_toast_important_error, prepare_claim_rewards_result.kmd_rewards_info.error) return false } - else { - text_error.text = "" - return true - } + + return true } function claimRewards() { @@ -77,7 +76,6 @@ DefaultModal { function reset() { prepare_claim_rewards_result = default_prepare_claim_rewards_result send_result = "" - text_error.text = "" } // Inside modal @@ -97,7 +95,6 @@ DefaultModal { } DefaultText { - visible: text_error.text === "" color: positive_claim_amount ? Style.colorText : Style.colorRed text_value: API.get().settings_pg.empty_string + (positive_claim_amount ? @@ -105,6 +102,13 @@ DefaultModal { : qsTr("Transaction fee is higher than the reward!")) } + DefaultButton { + text: API.get().settings_pg.empty_string + (qsTr("Refresh")) + onClicked: { + if(!prepareClaimRewards()) root.close() + } + } + // List header Item { Layout.topMargin: 30 @@ -377,12 +381,6 @@ DefaultModal { } } - DefaultText { - id: text_error - color: Style.colorRed - visible: text !== '' - } - // Buttons RowLayout { DefaultButton { diff --git a/atomic_qt_design/qml/Wallet/Main.qml b/atomic_qt_design/qml/Wallet/Main.qml index 1f34c232b2..a2d9f4f4c4 100644 --- a/atomic_qt_design/qml/Wallet/Main.qml +++ b/atomic_qt_design/qml/Wallet/Main.qml @@ -346,8 +346,8 @@ Item { visible: API.get().current_coin_info.is_claimable === true enabled: claim_rewards_modal.canClaim() onClicked: { - claim_rewards_modal.prepareClaimRewards() - claim_rewards_modal.open() + if(claim_rewards_modal.prepareClaimRewards()) + claim_rewards_modal.open() } } From 44bdaf7f702d691eb405d88bc245c111e566a89e Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 12 Aug 2020 00:03:02 +0300 Subject: [PATCH 276/515] feat(gui): adjust margins --- atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml index a67ee87861..97b97e80d8 100644 --- a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml +++ b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml @@ -103,6 +103,7 @@ DefaultModal { } DefaultButton { + Layout.topMargin: 15 text: API.get().settings_pg.empty_string + (qsTr("Refresh")) onClicked: { if(!prepareClaimRewards()) root.close() @@ -111,7 +112,7 @@ DefaultModal { // List header Item { - Layout.topMargin: 30 + Layout.topMargin: 15 Layout.fillWidth: true height: 40 From 569e553400d0c2179aa76bf4c5e21f153222fd56 Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 12 Aug 2020 00:08:48 +0300 Subject: [PATCH 277/515] feat(gui): use list index for utxos --- atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml index 97b97e80d8..5106a385a9 100644 --- a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml +++ b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml @@ -259,7 +259,7 @@ DefaultModal { font.pixelSize: Style.textSizeSmall1 - text_value: API.get().settings_pg.empty_string + ("#" + modelData.output_index) + text_value: API.get().settings_pg.empty_string + ("#" + (index + 1)) anchors.verticalCenter: parent.verticalCenter } From 1e30e8cd906373b4223fa97b9f3d8851a3e05c7c Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 12 Aug 2020 00:10:30 +0300 Subject: [PATCH 278/515] =?UTF-8?q?feat(gui):=20add=20error=20emoji=20?= =?UTF-8?q?=E2=9D=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml index 5106a385a9..f2db0b8dc8 100644 --- a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml +++ b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml @@ -99,7 +99,7 @@ DefaultModal { text_value: API.get().settings_pg.empty_string + (positive_claim_amount ? qsTr("You will receive %1", "AMT TICKER").arg(General.formatCrypto("", prepare_claim_rewards_result.withdraw_answer.my_balance_change, API.get().current_coin_info.ticker)) - : qsTr("Transaction fee is higher than the reward!")) + : ("❌ " + qsTr("Transaction fee is higher than the reward!"))) } DefaultButton { @@ -365,7 +365,7 @@ DefaultModal { break } - return API.get().settings_pg.empty_string + (val) + return API.get().settings_pg.empty_string + ("❌ " + val) } anchors.verticalCenter: parent.verticalCenter From 4e78f55156013a8fff1c62a92459658964da716d Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 12 Aug 2020 00:15:33 +0300 Subject: [PATCH 279/515] feat(gui): change duration format --- atomic_qt_design/qml/Constants/General.qml | 2 +- atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/atomic_qt_design/qml/Constants/General.qml b/atomic_qt_design/qml/Constants/General.qml index a2fc5d1b0a..310660dddc 100644 --- a/atomic_qt_design/qml/Constants/General.qml +++ b/atomic_qt_design/qml/Constants/General.qml @@ -79,7 +79,7 @@ QtObject { let seconds = Math.floor(delta) % 60 if(seconds < 10) seconds = '0' + seconds - return days + ':' + hours + ':' + minutes + ':' + seconds + return qsTr("%n day(s)", "", days) + ' ' + hours + ':' + minutes + ':' + seconds } function clone(obj) { diff --git a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml index f2db0b8dc8..9e058a6aca 100644 --- a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml +++ b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml @@ -169,7 +169,7 @@ DefaultModal { DefaultText { id: accruing_start_header - text_value: API.get().settings_pg.empty_string + (qsTr("Accruing Start At")) + text_value: API.get().settings_pg.empty_string + (qsTr("Accruing Started At")) font.pixelSize: utxo_header.font.pixelSize font.bold: utxo_header.font.bold @@ -201,7 +201,7 @@ DefaultModal { DefaultText { id: time_left_header - text_value: API.get().settings_pg.empty_string + (qsTr("Time Left (d:hh:mm:ss)")) + text_value: API.get().settings_pg.empty_string + (qsTr("Time Left")) font.pixelSize: utxo_header.font.pixelSize font.bold: utxo_header.font.bold From a83bc88ed7b0d7a3147200ea011381ba59400e42 Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 12 Aug 2020 00:21:20 +0300 Subject: [PATCH 280/515] feat(gui): move refresh button to top right and change it's color --- .../qml/Wallet/ClaimRewardsModal.qml | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml index 9e058a6aca..2a298e039d 100644 --- a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml +++ b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml @@ -94,19 +94,24 @@ DefaultModal { title: API.get().settings_pg.empty_string + (qsTr("Claim your %1 reward?", "TICKER").arg(API.get().current_coin_info.ticker)) } - DefaultText { - color: positive_claim_amount ? Style.colorText : Style.colorRed - text_value: API.get().settings_pg.empty_string + - (positive_claim_amount ? - qsTr("You will receive %1", "AMT TICKER").arg(General.formatCrypto("", prepare_claim_rewards_result.withdraw_answer.my_balance_change, API.get().current_coin_info.ticker)) - : ("❌ " + qsTr("Transaction fee is higher than the reward!"))) - } - DefaultButton { - Layout.topMargin: 15 - text: API.get().settings_pg.empty_string + (qsTr("Refresh")) - onClicked: { - if(!prepareClaimRewards()) root.close() + RowLayout { + Layout.fillWidth: true + DefaultText { + Layout.fillWidth: true + color: positive_claim_amount ? Style.colorText : Style.colorRed + text_value: API.get().settings_pg.empty_string + + (positive_claim_amount ? + qsTr("You will receive %1", "AMT TICKER").arg(General.formatCrypto("", prepare_claim_rewards_result.withdraw_answer.my_balance_change, API.get().current_coin_info.ticker)) + : ("❌ " + qsTr("Transaction fee is higher than the reward!"))) + } + + PrimaryButton { + Layout.topMargin: 15 + text: API.get().settings_pg.empty_string + (qsTr("Refresh")) + onClicked: { + if(!prepareClaimRewards()) root.close() + } } } @@ -128,7 +133,7 @@ DefaultModal { horizontalAlignment: Text.AlignLeft anchors.left: parent.left - anchors.leftMargin: parent.width * 0.03 + anchors.leftMargin: parent.width * 0.000 anchors.verticalCenter: parent.verticalCenter } From eb6a44111cbd82a0bda9acb85151f2d414f7716d Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 12 Aug 2020 00:25:40 +0300 Subject: [PATCH 281/515] feat(gui): add read more about kmd rewards article link --- atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml index 2a298e039d..983761f333 100644 --- a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml +++ b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml @@ -107,7 +107,6 @@ DefaultModal { } PrimaryButton { - Layout.topMargin: 15 text: API.get().settings_pg.empty_string + (qsTr("Refresh")) onClicked: { if(!prepareClaimRewards()) root.close() @@ -115,9 +114,19 @@ DefaultModal { } } + DefaultText { + Layout.alignment: Qt.AlignHCenter + text_value: API.get().settings_pg.empty_string + (General.cex_icon + ' ' + qsTr('Read more about KMD active users rewards') + '') + wrapMode: Text.WordWrap + font.pixelSize: Style.textSizeSmall2 + + onLinkActivated: Qt.openUrlExternally(link) + linkColor: color + } + // List header Item { - Layout.topMargin: 15 + Layout.topMargin: 25 Layout.fillWidth: true height: 40 From 958417abd925222662aff4c5f674b43f6f12b1ed Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 12 Aug 2020 00:30:50 +0300 Subject: [PATCH 282/515] feat(gui): take hyperlinks out of qsTr --- atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml | 4 ++-- atomic_qt_design/qml/Screens/Dashboard.qml | 2 +- atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml | 1 - 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml index 7870b8f410..528c16d620 100644 --- a/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml +++ b/atomic_qt_design/qml/Exchange/Trade/ConfirmTradeModal.qml @@ -119,7 +119,7 @@ DefaultModal { DefaultText { visible: config_section.is_dpow_configurable Layout.alignment: Qt.AlignHCenter - text_value: API.get().settings_pg.empty_string + (General.cex_icon + " " + qsTr('Read more about dPoW')) + text_value: API.get().settings_pg.empty_string + (General.cex_icon + ' ' + qsTr('Read more about dPoW') + '') wrapMode: Text.WordWrap font.pixelSize: Style.textSizeSmall2 @@ -157,7 +157,7 @@ DefaultModal { DefaultText { visible: enable_dpow_confs.visible && enable_dpow_confs.enabled Layout.alignment: Qt.AlignHCenter - text_value: API.get().settings_pg.empty_string + (General.cex_icon + " " + qsTr('Read more about dPoW')) + text_value: API.get().settings_pg.empty_string + (General.cex_icon + ' ' + qsTr('Read more about dPoW') + '') wrapMode: Text.WordWrap font.pixelSize: Style.textSizeSmall2 diff --git a/atomic_qt_design/qml/Screens/Dashboard.qml b/atomic_qt_design/qml/Screens/Dashboard.qml index 0b20cd84ae..cbed35ff11 100644 --- a/atomic_qt_design/qml/Screens/Dashboard.qml +++ b/atomic_qt_design/qml/Screens/Dashboard.qml @@ -221,7 +221,7 @@ Item { } DefaultText { - text_value: API.get().settings_pg.empty_string + (qsTr('Markets data (prices, charts, etc.) marked with the ⓘ icon originates from third party sources. (coinpaprika.com)')) + text_value: API.get().settings_pg.empty_string + (qsTr('Markets data (prices, charts, etc.) marked with the ⓘ icon originates from third party sources.') + ' (coinpaprika.com)') wrapMode: Text.WordWrap Layout.preferredWidth: cex_rates_modal.width diff --git a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml index 983761f333..46ab5aeed0 100644 --- a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml +++ b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml @@ -115,7 +115,6 @@ DefaultModal { } DefaultText { - Layout.alignment: Qt.AlignHCenter text_value: API.get().settings_pg.empty_string + (General.cex_icon + ' ' + qsTr('Read more about KMD active users rewards') + '') wrapMode: Text.WordWrap font.pixelSize: Style.textSizeSmall2 From 9c33dd767b69cf4bf2ef1259773a0eb1645d59de Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 12 Aug 2020 00:43:37 +0300 Subject: [PATCH 283/515] feat(gui): add No UTXOs eligible for claiming case --- .../qml/Wallet/ClaimRewardsModal.qml | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml index 46ab5aeed0..5ce02189bd 100644 --- a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml +++ b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml @@ -9,6 +9,17 @@ DefaultModal { id: root readonly property bool positive_claim_amount: parseFloat(prepare_claim_rewards_result.withdraw_answer.my_balance_change) > 0 + readonly property bool has_eligible_utxo: { + const utxos = prepare_claim_rewards_result.kmd_rewards_info.result + if(!utxos) return false + + for(let i = 0; i < utxos.length; ++i) + if(!utxos[i].accrued_rewards.NotAccruedReason) + return true + + return false + } + readonly property bool can_confirm: positive_claim_amount && has_eligible_utxo readonly property var default_prepare_claim_rewards_result: ({ "kmd_rewards_info": { @@ -99,11 +110,12 @@ DefaultModal { Layout.fillWidth: true DefaultText { Layout.fillWidth: true - color: positive_claim_amount ? Style.colorText : Style.colorRed - text_value: API.get().settings_pg.empty_string + - (positive_claim_amount ? - qsTr("You will receive %1", "AMT TICKER").arg(General.formatCrypto("", prepare_claim_rewards_result.withdraw_answer.my_balance_change, API.get().current_coin_info.ticker)) - : ("❌ " + qsTr("Transaction fee is higher than the reward!"))) + color: can_confirm ? Style.colorText : Style.colorRed + text_value: API.get().settings_pg.empty_string + ( + !has_eligible_utxo ? ("❌ " + qsTr("No UTXOs eligible for claiming")) : + !positive_claim_amount ? ("❌ " + qsTr("Transaction fee is higher than the reward!")) : + + qsTr("You will receive %1", "AMT TICKER").arg(General.formatCrypto("", prepare_claim_rewards_result.withdraw_answer.my_balance_change, API.get().current_coin_info.ticker))) } PrimaryButton { @@ -406,7 +418,7 @@ DefaultModal { text: API.get().settings_pg.empty_string + (qsTr("Confirm")) Layout.fillWidth: true onClicked: claimRewards() - enabled: positive_claim_amount + enabled: can_confirm } } } From 43753fa39ff22efc07744e4eff64e36568275e17 Mon Sep 17 00:00:00 2001 From: milerius Date: Wed, 12 Aug 2020 06:44:15 +0200 Subject: [PATCH 284/515] feat(notifications): add notification property --- assets/config/cfg.json | 1 + .../assets/languages/atomic_qt_en.ts | 150 ++++++++++++----- .../assets/languages/atomic_qt_fr.ts | 154 +++++++++++++----- .../assets/languages/atomic_qt_tr.ts | 154 +++++++++++++----- src/atomic.dex.cfg.cpp | 12 ++ src/atomic.dex.cfg.hpp | 2 + src/atomic.dex.qt.settings.page.cpp | 68 +++++--- src/atomic.dex.qt.settings.page.hpp | 12 +- 8 files changed, 415 insertions(+), 138 deletions(-) diff --git a/assets/config/cfg.json b/assets/config/cfg.json index 6bec5b5a4e..675c72daab 100644 --- a/assets/config/cfg.json +++ b/assets/config/cfg.json @@ -1,4 +1,5 @@ { + "notification_enabled": true, "lang": "en", "available_lang": [ "en", diff --git a/atomic_qt_design/assets/languages/atomic_qt_en.ts b/atomic_qt_design/assets/languages/atomic_qt_en.ts index 975485149a..2b08ae8029 100644 --- a/atomic_qt_design/assets/languages/atomic_qt_en.ts +++ b/atomic_qt_design/assets/languages/atomic_qt_en.ts @@ -50,29 +50,109 @@ ClaimRewardsModal - + Failed to prepare to claim rewards - + + Failed to get the rewards info + + + + Claim your %1 reward? TICKER - + You will receive %1 AMT TICKER - + + Transaction fee is higher than the reward! + + + + + UTXO + + + + + Amount + + + + + Reward + + + + + Accruing Start At + + + + + Accruing Stop At + + + + + Time Left (d:hh:mm:ss) + + + + + Error + + + + + Locktime is not set + + + + + Locktime is less than the threshold + + + + + UTXO height is greater than end of the era + + + + + UTXO amount is less than 10 + + + + + One hour did not pass yet + + + + + Transaction is in mempool + + + + + Unknown problem + + + + Cancel - + Confirm @@ -95,58 +175,54 @@ - + Security configuration - - - dPoW protected - - - %1 confirmations for incoming transactions + dPoW protected - + Use custom protection settings for incoming %1 transactions TICKER - + Enable Komodo dPoW security - + + <a href="https://komodoplatform.com/security-delayed-proof-of-work-dpow/">Read more about dPoW</a> - - Warning, this atomic swap is not dPoW protected! + + %1 confirmations for incoming %2 transactions - - Change required confirmations + + Required Confirmations - - Confirmations + + Warning, this atomic swap is not dPoW protected! - + Cancel - + Confirm @@ -664,32 +740,32 @@ NotificationsPanel - + Swap status updated - + AtomicDEX Pro - + Notifications - + Clear - + There isn't any notification - + Close @@ -1518,43 +1594,43 @@ Trade - + Placed the order - + Failed to place the order - + Please fill the price field - + %1 balance is lower than minimum trade amount - + Not enough balance for the fees. Need at least %1 more AMT TICKER - + Please fill the volume field - + Not enough ETH for the transaction fee - + Amount is lower than minimum trade amount diff --git a/atomic_qt_design/assets/languages/atomic_qt_fr.ts b/atomic_qt_design/assets/languages/atomic_qt_fr.ts index af182082d7..0577fd48ff 100644 --- a/atomic_qt_design/assets/languages/atomic_qt_fr.ts +++ b/atomic_qt_design/assets/languages/atomic_qt_fr.ts @@ -57,29 +57,109 @@ ClaimRewardsModal - + Failed to prepare to claim rewards - + + Failed to get the rewards info + + + + Claim your %1 reward? TICKER Réclamer votre %1 récompense ? - + You will receive %1 AMT TICKER Vous allez recevoir %1 - + + Transaction fee is higher than the reward! + + + + + UTXO + + + + + Amount + Montant + + + + Reward + + + + + Accruing Start At + + + + + Accruing Stop At + + + + + Time Left (d:hh:mm:ss) + + + + + Error + + + + + Locktime is not set + + + + + Locktime is less than the threshold + + + + + UTXO height is greater than end of the era + + + + + UTXO amount is less than 10 + + + + + One hour did not pass yet + + + + + Transaction is in mempool + + + + + Unknown problem + + + + Cancel Annuler - + Confirm Confirmer @@ -102,58 +182,58 @@ Cette transaction peut prendre jusqu'à 10 mins - NE fermez pas l'application ! - + Security configuration - - - dPoW protected - - - %1 confirmations for incoming transactions + dPoW protected - + Use custom protection settings for incoming %1 transactions TICKER - + Enable Komodo dPoW security - + + <a href="https://komodoplatform.com/security-delayed-proof-of-work-dpow/">Read more about dPoW</a> - - Warning, this atomic swap is not dPoW protected! + + %1 confirmations for incoming %2 transactions - - Change required confirmations + + Required Confirmations + + + + + Warning, this atomic swap is not dPoW protected! - Confirmations - Confirmations + Confirmations - + Cancel Annuler - + Confirm Confirmer @@ -683,32 +763,32 @@ NotificationsPanel - + Swap status updated - + AtomicDEX Pro AtomicDEX Pro - + Notifications - + Clear - + There isn't any notification - + Close Fermer @@ -1713,43 +1793,43 @@ Impossible de placer l'ordre. - + Placed the order - + Failed to place the order - + Please fill the price field - + %1 balance is lower than minimum trade amount - + Not enough balance for the fees. Need at least %1 more AMT TICKER - + Please fill the volume field - + Not enough ETH for the transaction fee Pas assez d'ETH pour les frais de transaction - + Amount is lower than minimum trade amount diff --git a/atomic_qt_design/assets/languages/atomic_qt_tr.ts b/atomic_qt_design/assets/languages/atomic_qt_tr.ts index 5f4869aa10..986e9c0dda 100644 --- a/atomic_qt_design/assets/languages/atomic_qt_tr.ts +++ b/atomic_qt_design/assets/languages/atomic_qt_tr.ts @@ -61,29 +61,109 @@ ClaimRewardsModal - + Failed to prepare to claim rewards - + + Failed to get the rewards info + + + + Claim your %1 reward? TICKER %1 ödülünüzü alacak mısınız? - + You will receive %1 AMT TICKER %1 alacaksınız - + + Transaction fee is higher than the reward! + + + + + UTXO + + + + + Amount + Miktar + + + + Reward + + + + + Accruing Start At + + + + + Accruing Stop At + + + + + Time Left (d:hh:mm:ss) + + + + + Error + + + + + Locktime is not set + + + + + Locktime is less than the threshold + + + + + UTXO height is greater than end of the era + + + + + UTXO amount is less than 10 + + + + + One hour did not pass yet + + + + + Transaction is in mempool + + + + + Unknown problem + + + + Cancel İptal - + Confirm Onayla @@ -106,58 +186,58 @@ Bu işlem 10 dakika kadar sürebilir - Programı KAPATMAYINIZ! - + Security configuration - - - dPoW protected - - - %1 confirmations for incoming transactions + dPoW protected - + Use custom protection settings for incoming %1 transactions TICKER - + Enable Komodo dPoW security - + + <a href="https://komodoplatform.com/security-delayed-proof-of-work-dpow/">Read more about dPoW</a> - - Warning, this atomic swap is not dPoW protected! + + %1 confirmations for incoming %2 transactions - - Change required confirmations + + Required Confirmations + + + + + Warning, this atomic swap is not dPoW protected! - Confirmations - Onay Sayısı + Onay Sayısı - + Cancel İptal - + Confirm Onayla @@ -685,32 +765,32 @@ NotificationsPanel - + Swap status updated - + AtomicDEX Pro AtomıcDEX Pro - + Notifications - + Clear - + There isn't any notification - + Close Kapat @@ -1714,43 +1794,43 @@ Al-Sat - + Placed the order - + Failed to place the order - + Please fill the price field - + %1 balance is lower than minimum trade amount - + Not enough balance for the fees. Need at least %1 more AMT TICKER - + Please fill the volume field - + Not enough ETH for the transaction fee - + Amount is lower than minimum trade amount diff --git a/src/atomic.dex.cfg.cpp b/src/atomic.dex.cfg.cpp index 49cae251ef..c29074ab0f 100644 --- a/src/atomic.dex.cfg.cpp +++ b/src/atomic.dex.cfg.cpp @@ -34,6 +34,7 @@ namespace config_json_data["current_currency_sign"] = config.current_currency_sign; config_json_data["current_fiat_sign"] = config.current_fiat_sign; config_json_data["available_signs"] = config.available_currency_signs; + config_json_data["notification_enabled"] = config.notification_enabled; ifs.close(); @@ -58,6 +59,17 @@ namespace atomic_dex j.at("current_currency_sign").get_to(config.current_currency_sign); j.at("available_signs").get_to(config.available_currency_signs); j.at("current_fiat_sign").get_to(config.current_fiat_sign); + j.at("notification_enabled").get_to(config.notification_enabled); + } + + void + change_notification_status(cfg& config, bool is_enabled) + { + if (config.notification_enabled != is_enabled) + { + config.notification_enabled = is_enabled; + upgrade_cfg(config); + } } void diff --git a/src/atomic.dex.cfg.hpp b/src/atomic.dex.cfg.hpp index 0bb1dfe0cd..c11f37f18f 100644 --- a/src/atomic.dex.cfg.hpp +++ b/src/atomic.dex.cfg.hpp @@ -31,12 +31,14 @@ namespace atomic_dex std::vector available_lang; std::vector available_fiat; std::array possible_currencies; + bool notification_enabled; }; void from_json(const nlohmann::json& j, cfg& config); void change_lang(cfg& config, const std::string& new_lang); void change_currency(cfg& config, const std::string& new_currency); void change_fiat(cfg& config, const std::string& new_fiat); + void change_notification_status(cfg& config, bool is_enabled); [[nodiscard]] bool is_this_currency_a_fiat(cfg& config, const std::string& currency) noexcept; cfg load_cfg(); std::string retrieve_sign_from_ticker(const cfg& config, const std::string& currency) noexcept; diff --git a/src/atomic.dex.qt.settings.page.cpp b/src/atomic.dex.qt.settings.page.cpp index 589fd0bacc..3f0d11a7c1 100644 --- a/src/atomic.dex.qt.settings.page.cpp +++ b/src/atomic.dex.qt.settings.page.cpp @@ -19,13 +19,16 @@ #include //! Project Headers -#include "atomic.dex.qt.settings.page.hpp" #include "atomic.dex.events.hpp" +#include "atomic.dex.qt.settings.page.hpp" //! Constructo destructor namespace atomic_dex { - settings_page::settings_page(entt::registry& registry, std::shared_ptr app, QObject* parent) noexcept : QObject(parent), system(registry), m_app(app) {} + settings_page::settings_page(entt::registry& registry, std::shared_ptr app, QObject* parent) noexcept : + QObject(parent), system(registry), m_app(app) + { + } } // namespace atomic_dex //! Override @@ -40,7 +43,8 @@ namespace atomic_dex //! Properties namespace atomic_dex { - QString settings_page::get_empty_string() const noexcept + QString + settings_page::get_empty_string() const noexcept { return m_empty_string; } @@ -58,20 +62,20 @@ namespace atomic_dex change_lang(m_config, new_lang_std); auto get_locale = [](const std::string& current_lang) { - if (current_lang == "tr") - { - return QLocale::Language::Turkish; - } - if (current_lang == "en") - { - return QLocale::Language::English; - } - if (current_lang == "fr") - { - return QLocale::Language::French; - } - return QLocale::Language::AnyLanguage; - }; + if (current_lang == "tr") + { + return QLocale::Language::Turkish; + } + if (current_lang == "en") + { + return QLocale::Language::English; + } + if (current_lang == "fr") + { + return QLocale::Language::French; + } + return QLocale::Language::AnyLanguage; + }; qDebug() << "locale before: " << QLocale().name(); QLocale::setDefault(get_locale(m_config.current_lang)); @@ -83,6 +87,22 @@ namespace atomic_dex emit langChanged(); } + bool + atomic_dex::settings_page::is_notification_enabled() const noexcept + { + return m_config.notification_enabled; + } + + void + settings_page::set_notification_enabled(bool is_enabled) noexcept + { + if (m_config.notification_enabled != is_enabled) + { + change_notification_status(m_config, is_enabled); + emit onNotificationEnabledChanged(); + } + } + QString settings_page::get_current_currency_sign() const noexcept { @@ -136,22 +156,24 @@ namespace atomic_dex //! Public API namespace atomic_dex { - atomic_dex::cfg& settings_page::get_cfg() noexcept + atomic_dex::cfg& + settings_page::get_cfg() noexcept { return m_config; } - const atomic_dex::cfg& settings_page::get_cfg() const noexcept + const atomic_dex::cfg& + settings_page::get_cfg() const noexcept { return m_config; - } - void settings_page::init_lang() noexcept + void + settings_page::init_lang() noexcept { set_current_lang(QString::fromStdString(m_config.current_lang)); } -} +} // namespace atomic_dex //! QML API namespace atomic_dex @@ -182,4 +204,4 @@ namespace atomic_dex for (auto&& cur_currency: m_config.possible_currencies) { out.push_back(QString::fromStdString(cur_currency)); } return out; } -} \ No newline at end of file +} // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.settings.page.hpp b/src/atomic.dex.qt.settings.page.hpp index 0d376339c0..cf683c02f1 100644 --- a/src/atomic.dex.qt.settings.page.hpp +++ b/src/atomic.dex.qt.settings.page.hpp @@ -42,6 +42,7 @@ namespace atomic_dex Q_PROPERTY(QString current_currency_sign READ get_current_currency_sign NOTIFY onCurrencySignChanged) Q_PROPERTY(QString current_fiat_sign READ get_current_fiat_sign NOTIFY onFiatSignChanged) Q_PROPERTY(QString current_fiat READ get_current_fiat WRITE set_current_fiat NOTIFY onFiatChanged) + Q_PROPERTY(bool notification_enabled READ is_notification_enabled WRITE set_notification_enabled NOTIFY onNotificationEnabledChanged) //! Private member fields Fields std::shared_ptr m_app; @@ -64,18 +65,20 @@ namespace atomic_dex [[nodiscard]] QString get_current_currency_sign() const noexcept; [[nodiscard]] QString get_current_fiat_sign() const noexcept; [[nodiscard]] QString get_current_fiat() const noexcept; + [[nodiscard]] bool is_notification_enabled() const noexcept; + void set_notification_enabled(bool is_enabled) noexcept; void set_current_currency(const QString& current_currency) noexcept; void set_current_fiat(const QString& current_fiat) noexcept; //! Public API [[nodiscard]] atomic_dex::cfg& get_cfg() noexcept; [[nodiscard]] const atomic_dex::cfg& get_cfg() const noexcept; - void init_lang() noexcept; + void init_lang() noexcept; //! Public QML API - Q_INVOKABLE QStringList get_available_langs() const; - Q_INVOKABLE QStringList get_available_fiats() const; - Q_INVOKABLE QStringList get_available_currencies() const; + Q_INVOKABLE QStringList get_available_langs() const; + Q_INVOKABLE QStringList get_available_fiats() const; + Q_INVOKABLE QStringList get_available_currencies() const; signals: void onLangChanged(); @@ -84,6 +87,7 @@ namespace atomic_dex void onCurrencySignChanged(); void onFiatSignChanged(); void onFiatChanged(); + void onNotificationEnabledChanged(); }; } // namespace atomic_dex From 6caf922dbc5966e5b0a3b0010f730acd5e1e8a6c Mon Sep 17 00:00:00 2001 From: milerius Date: Wed, 12 Aug 2020 13:33:24 +0200 Subject: [PATCH 285/515] feat(notifications): remove is_claiming_ready and update send_rewards --- src/atomic.dex.app.cpp | 4 ++-- src/atomic.dex.app.hpp | 2 +- src/atomic.dex.mm2.cpp | 8 ++++---- src/atomic.dex.mm2.hpp | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index 7c8ec20bdb..26a39fa5fa 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -478,11 +478,11 @@ namespace atomic_dex return to_qt_binding(std::move(answer), this, QString::fromStdString(coin.explorer_url[0])); } - bool + /*bool atomic_dex::application::is_claiming_ready(const QString& ticker) { return get_mm2().is_claiming_ready(ticker.toStdString()); - } + }*/ QVariant atomic_dex::application::claim_rewards(const QString& ticker) diff --git a/src/atomic.dex.app.hpp b/src/atomic.dex.app.hpp index 28d3988ac2..307a34d7ed 100644 --- a/src/atomic.dex.app.hpp +++ b/src/atomic.dex.app.hpp @@ -200,7 +200,7 @@ namespace atomic_dex Q_INVOKABLE static QString get_price_amount(const QString& base_amount, const QString& rel_amount); Q_INVOKABLE bool do_i_have_enough_funds(const QString& ticker, const QString& amount) const; Q_INVOKABLE bool disable_coins(const QStringList& coins); - Q_INVOKABLE bool is_claiming_ready(const QString& ticker); + //Q_INVOKABLE bool is_claiming_ready(const QString& ticker); Q_INVOKABLE QVariant claim_rewards(const QString& ticker); diff --git a/src/atomic.dex.mm2.cpp b/src/atomic.dex.mm2.cpp index 905856c0ab..8bb33521a5 100644 --- a/src/atomic.dex.mm2.cpp +++ b/src/atomic.dex.mm2.cpp @@ -1023,7 +1023,7 @@ namespace atomic_dex return m_tx_state.at(ticker); } - bool + /*bool mm2::is_claiming_ready(const std::string& ticker) const noexcept { spdlog::debug("{} l{} f[{}]", __FUNCTION__, __LINE__, fs::path(__FILE__).filename().string()); @@ -1044,7 +1044,7 @@ namespace atomic_dex return true; } return false; - } + }*/ nlohmann::json mm2::claim_rewards(const std::string& ticker, t_mm2_ec& ec) noexcept @@ -1075,13 +1075,13 @@ namespace atomic_dex spdlog::debug("{} l{} f[{}]", __FUNCTION__, __LINE__, fs::path(__FILE__).filename().string()); auto ticker = req.coin; auto b_answer = mm2::broadcast(std::move(req), ec); - if (!ec) + /*if (!ec) { auto lock_claim_file_path = fs::temp_directory_path() / (ticker + ".claim.lock"); std::ofstream ofs(lock_claim_file_path.string()); assert(ofs); spdlog::info("created file {}", lock_claim_file_path.string()); - } + }*/ return b_answer; } diff --git a/src/atomic.dex.mm2.hpp b/src/atomic.dex.mm2.hpp index 5dc930191e..c2f2dc3f63 100644 --- a/src/atomic.dex.mm2.hpp +++ b/src/atomic.dex.mm2.hpp @@ -213,7 +213,7 @@ namespace atomic_dex [[nodiscard]] t_tx_state get_tx_state(const std::string& ticker, t_mm2_ec& ec) const; //! Claim Reward is possible on this specific ticker ? - [[nodiscard]] bool is_claiming_ready(const std::string& ticker) const noexcept; + //[[nodiscard]] bool is_claiming_ready(const std::string& ticker) const noexcept; //! Claim rewards nlohmann::json claim_rewards(const std::string& ticker, t_mm2_ec& ec) noexcept; From 647412d478b4d220dc312a33d96bb4ea0936bc3c Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 12 Aug 2020 15:38:09 +0300 Subject: [PATCH 286/515] feat(gui): remove is_claiming_ready --- atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml index 5ce02189bd..b884584ba3 100644 --- a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml +++ b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml @@ -56,8 +56,7 @@ DefaultModal { // Local function canClaim() { return API.get().current_coin_info.is_claimable === true && - API.get().do_i_have_enough_funds(API.get().current_coin_info.ticker, API.get().current_coin_info.minimal_balance_for_asking_rewards) && - API.get().is_claiming_ready(API.get().current_coin_info.ticker) + API.get().do_i_have_enough_funds(API.get().current_coin_info.ticker, API.get().current_coin_info.minimal_balance_for_asking_rewards) } function prepareClaimRewards() { From d1d96e6ff32c33aa44e6d465ccd2b1838483d267 Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 12 Aug 2020 15:38:26 +0300 Subject: [PATCH 287/515] feat(gui): display "-" if accrue_stop_at is undefined --- atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml index b884584ba3..1a442d8a3b 100644 --- a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml +++ b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml @@ -335,7 +335,7 @@ DefaultModal { font.pixelSize: utxo_value.font.pixelSize - text_value: API.get().settings_pg.empty_string + (modelData.accrue_stop_at_human_date) + text_value: API.get().settings_pg.empty_string + (modelData.accrue_stop_at ? modelData.accrue_stop_at_human_date : "-") anchors.verticalCenter: parent.verticalCenter } @@ -348,7 +348,7 @@ DefaultModal { font.pixelSize: utxo_value.font.pixelSize - text_value: API.get().settings_pg.empty_string + (General.secondsToTimeLeft(Date.now()/1000, modelData.accrue_stop_at)) + text_value: API.get().settings_pg.empty_string + (modelData.accrue_stop_at ? General.secondsToTimeLeft(Date.now()/1000, modelData.accrue_stop_at) : '-') anchors.verticalCenter: parent.verticalCenter } From 612022fcd1afec46cde4b0ab8620cfc4e28ad5a2 Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 12 Aug 2020 15:59:19 +0300 Subject: [PATCH 288/515] feat(gui): remove minimal_balance_for_asking_rewards --- atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml | 3 +-- atomic_qt_design/qml/Wallet/Main.qml | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml index 1a442d8a3b..7069c0b098 100644 --- a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml +++ b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml @@ -55,8 +55,7 @@ DefaultModal { // Local function canClaim() { - return API.get().current_coin_info.is_claimable === true && - API.get().do_i_have_enough_funds(API.get().current_coin_info.ticker, API.get().current_coin_info.minimal_balance_for_asking_rewards) + return API.get().current_coin_info.is_claimable && parseFloat(API.get().current_coin_info.balance) > 0 } function prepareClaimRewards() { diff --git a/atomic_qt_design/qml/Wallet/Main.qml b/atomic_qt_design/qml/Wallet/Main.qml index a2d9f4f4c4..008b694d90 100644 --- a/atomic_qt_design/qml/Wallet/Main.qml +++ b/atomic_qt_design/qml/Wallet/Main.qml @@ -343,7 +343,7 @@ Item { id: button_claim_rewards text: API.get().settings_pg.empty_string + (qsTr("Claim Rewards")) - visible: API.get().current_coin_info.is_claimable === true + visible: API.get().current_coin_info.is_claimable enabled: claim_rewards_modal.canClaim() onClicked: { if(claim_rewards_modal.prepareClaimRewards()) From 6862c887471d482a4d9984a2ca3a44106b9206b5 Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 12 Aug 2020 16:13:23 +0300 Subject: [PATCH 289/515] feat(gui): remove unnecessary code --- atomic_qt_design/qml/Wallet/Main.qml | 2 -- 1 file changed, 2 deletions(-) diff --git a/atomic_qt_design/qml/Wallet/Main.qml b/atomic_qt_design/qml/Wallet/Main.qml index 008b694d90..ed6a0ecc92 100644 --- a/atomic_qt_design/qml/Wallet/Main.qml +++ b/atomic_qt_design/qml/Wallet/Main.qml @@ -353,8 +353,6 @@ Item { ClaimRewardsModal { id: claim_rewards_modal - - postClaim: () => { button_claim_rewards.enabled = claim_rewards_modal.canClaim() } } } } From 132ffc0f7f371cc84309dd617f2b7a97015f9466 Mon Sep 17 00:00:00 2001 From: milerius Date: Wed, 12 Aug 2020 17:06:40 +0200 Subject: [PATCH 290/515] feat(rewards): remove additional check --- src/atomic.dex.mm2.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/atomic.dex.mm2.cpp b/src/atomic.dex.mm2.cpp index 8bb33521a5..a6e41a0e9c 100644 --- a/src/atomic.dex.mm2.cpp +++ b/src/atomic.dex.mm2.cpp @@ -1053,9 +1053,9 @@ namespace atomic_dex nlohmann::json out = nlohmann::json::object(); const auto& info = get_coin_info(ticker); - if (not info.is_claimable || not do_i_have_enough_funds(ticker, t_float_50(info.minimal_claim_amount))) + if (not info.is_claimable) { - ec = not info.is_claimable ? dextop_error::ticker_is_not_claimable : dextop_error::claim_not_enough_funds; + ec = dextop_error::ticker_is_not_claimable; return {}; } t_withdraw_request req{.coin = ticker, .to = m_balance_informations.at(ticker).address, .amount = "0", .max = true}; From d4944048e0c082999fe5b88c1e17af7f2cd556c9 Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 12 Aug 2020 18:08:16 +0300 Subject: [PATCH 291/515] feat(gui): code polish --- atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml index 7069c0b098..f49104ce22 100644 --- a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml +++ b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml @@ -83,7 +83,7 @@ DefaultModal { } function reset() { - prepare_claim_rewards_result = default_prepare_claim_rewards_result + prepare_claim_rewards_result = General.clone(default_prepare_claim_rewards_result) send_result = "" } From 115a502a9c327f5d663e812c2e7ba2ef692644c3 Mon Sep 17 00:00:00 2001 From: naezith Date: Wed, 12 Aug 2020 18:36:39 +0300 Subject: [PATCH 292/515] feat(gui): fix accrue_start_at_human_date was undefined <10 kmd --- atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml index f49104ce22..89197fc22b 100644 --- a/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml +++ b/atomic_qt_design/qml/Wallet/ClaimRewardsModal.qml @@ -47,7 +47,7 @@ DefaultModal { "tx_hex": "" } }) - property var prepare_claim_rewards_result: default_prepare_claim_rewards_result + property var prepare_claim_rewards_result: General.clone(default_prepare_claim_rewards_result) property string send_result // Override @@ -321,7 +321,7 @@ DefaultModal { font.pixelSize: utxo_value.font.pixelSize - text_value: API.get().settings_pg.empty_string + (modelData.accrue_start_at_human_date) + text_value: API.get().settings_pg.empty_string + (modelData.accrue_start_at_human_date || "-") anchors.verticalCenter: parent.verticalCenter } @@ -334,7 +334,7 @@ DefaultModal { font.pixelSize: utxo_value.font.pixelSize - text_value: API.get().settings_pg.empty_string + (modelData.accrue_stop_at ? modelData.accrue_stop_at_human_date : "-") + text_value: API.get().settings_pg.empty_string + (modelData.accrue_stop_at_human_date || "-") anchors.verticalCenter: parent.verticalCenter } From ad5431b3d2d50d7c6b32907ea633e87dcd96d075 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Thu, 13 Aug 2020 06:59:05 +0200 Subject: [PATCH 293/515] feat(details_swap_progress): add expected event list as a function --- src/atomic.dex.qt.orders.model.cpp | 36 ++++++++++++++++++++++++++++++ src/atomic.dex.qt.orders.model.hpp | 3 +++ 2 files changed, 39 insertions(+) diff --git a/src/atomic.dex.qt.orders.model.cpp b/src/atomic.dex.qt.orders.model.cpp index b2088bd3d9..e2ddfb604e 100644 --- a/src/atomic.dex.qt.orders.model.cpp +++ b/src/atomic.dex.qt.orders.model.cpp @@ -541,4 +541,40 @@ namespace atomic_dex this->m_model_data.clear(); this->endResetModel(); } +} // namespace atomic_dex + +//! Public QML API +namespace atomic_dex +{ + QStringList + orders_model::get_expected_events_list(bool is_maker) const noexcept + { + if (is_maker) + { + return { + "Started", + "Negotiated", + "TakerFeeValidated", + "MakerPaymentSent", + "TakerPaymentReceived", + "TakerPaymentWaitConfirmStarted", + "TakerPaymentValidatedAndConfirmed", + "TakerPaymentSpent", + "Finished"}; + } + else + { + return { + "Started", + "Negotiated", + "TakerFeeSent", + "MakerPaymentReceived", + "MakerPaymentWaitConfirmStarted", + "MakerPaymentValidatedAndConfirmed", + "TakerPaymentSent", + "TakerPaymentSpent", + "MakerPaymentSpent", + "Finished"}; + } + } } // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.orders.model.hpp b/src/atomic.dex.qt.orders.model.hpp index 71472336fb..9a0621eca4 100644 --- a/src/atomic.dex.qt.orders.model.hpp +++ b/src/atomic.dex.qt.orders.model.hpp @@ -77,6 +77,9 @@ namespace atomic_dex //! Properties [[nodiscard]] int get_length() const noexcept; [[nodiscard]] orders_proxy_model* get_orders_proxy_mdl() const noexcept; + + //! QML_API + Q_INVOKABLE QStringList get_expected_events_list(bool is_maker) const noexcept; signals: void lengthChanged(); void ordersProxyChanged(); From 615da344b10e9b49431e52eaa0676784ad6560a4 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Thu, 13 Aug 2020 14:22:44 +0200 Subject: [PATCH 294/515] feat(orders): fix orders flipping for maker order --- src/atomic.dex.mm2.api.cpp | 2 +- src/atomic.dex.qt.orders.model.cpp | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/atomic.dex.mm2.api.cpp b/src/atomic.dex.mm2.api.cpp index 5b0c0daca9..0fefb51c66 100644 --- a/src/atomic.dex.mm2.api.cpp +++ b/src/atomic.dex.mm2.api.cpp @@ -668,7 +668,7 @@ namespace mm2::api using namespace date; const auto time_key = value.at("created_at").get(); - std::string action = "Buy"; + std::string action = ""; if (not is_maker) { value.at("request").at("action").get_to(action); diff --git a/src/atomic.dex.qt.orders.model.cpp b/src/atomic.dex.qt.orders.model.cpp index e2ddfb604e..85b8846a49 100644 --- a/src/atomic.dex.qt.orders.model.cpp +++ b/src/atomic.dex.qt.orders.model.cpp @@ -397,6 +397,11 @@ namespace atomic_dex .is_swap = false, .is_cancellable = contents.cancellable, .is_recoverable = false}; + if (contents.action.empty() && contents.order_type == "maker") + { + data.base_coin = QString::fromStdString(contents.base); + data.rel_coin = QString::fromStdString(contents.rel); + } data.ticker_pair = data.base_coin + "/" + data.rel_coin; this->m_orders_id_registry.emplace(contents.order_id); this->m_model_data.push_back(std::move(data)); From d4bd4586531f5b15fbd35f0ad6107403db02bfd8 Mon Sep 17 00:00:00 2001 From: naezith Date: Thu, 13 Aug 2020 15:52:32 +0300 Subject: [PATCH 295/515] feat(gui): persistent desktop notifications setting --- atomic_qt_design/qml/Constants/General.qml | 1 - atomic_qt_design/qml/Dashboard/NotificationsPanel.qml | 2 +- atomic_qt_design/qml/Settings/Settings.qml | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/atomic_qt_design/qml/Constants/General.qml b/atomic_qt_design/qml/Constants/General.qml index 310660dddc..279c0abbc4 100644 --- a/atomic_qt_design/qml/Constants/General.qml +++ b/atomic_qt_design/qml/Constants/General.qml @@ -19,7 +19,6 @@ QtObject { readonly property string privacy_text: "*****" property bool privacy_mode: false - property bool enable_desktop_notifications: true readonly property int idx_dashboard_portfolio: 0 readonly property int idx_dashboard_wallet: 1 diff --git a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml index 226554c2d1..577a5a05d3 100644 --- a/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml +++ b/atomic_qt_design/qml/Dashboard/NotificationsPanel.qml @@ -80,7 +80,7 @@ FloatingBackground { } function displayMessage(title, message) { - if(General.enable_desktop_notifications) + if(API.get().settings_pg.notification_enabled) tray.showMessage(title, message) } diff --git a/atomic_qt_design/qml/Settings/Settings.qml b/atomic_qt_design/qml/Settings/Settings.qml index 5182ae34c3..f25339e157 100644 --- a/atomic_qt_design/qml/Settings/Settings.qml +++ b/atomic_qt_design/qml/Settings/Settings.qml @@ -69,8 +69,8 @@ Item { Switch { Layout.alignment: Qt.AlignHCenter text: API.get().settings_pg.empty_string + (qsTr("Enable Desktop Notifications")) - Component.onCompleted: checked = General.enable_desktop_notifications - onCheckedChanged: General.enable_desktop_notifications = checked + Component.onCompleted: checked = API.get().settings_pg.notification_enabled + onCheckedChanged: API.get().settings_pg.notification_enabled = checked } DefaultButton { From 1b02e555499a2ad70035d0a1e7331885e51e0be6 Mon Sep 17 00:00:00 2001 From: naezith Date: Thu, 13 Aug 2020 17:20:55 +0300 Subject: [PATCH 296/515] feat(gui): scrollable order modal --- atomic_qt_design/qml/Exchange/OrderModal.qml | 227 ++++++++++--------- 1 file changed, 121 insertions(+), 106 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/OrderModal.qml b/atomic_qt_design/qml/Exchange/OrderModal.qml index b5f5d2738c..a8436eb574 100644 --- a/atomic_qt_design/qml/Exchange/OrderModal.qml +++ b/atomic_qt_design/qml/Exchange/OrderModal.qml @@ -9,6 +9,8 @@ DefaultModal { id: root width: 900 + height: window.height - 90 + property var details onDetailsChanged: { @@ -26,127 +28,140 @@ DefaultModal { details.is_swap ? qsTr("Swap Details") : qsTr("Order Details")) } - // Complete image - DefaultImage { - visible: !details ? false : - details.is_swap && details.order_status === "successful" - Layout.alignment: Qt.AlignHCenter - source: General.image_path + "exchange-trade-complete.svg" - } + DefaultFlickable { + Layout.fillWidth: true + Layout.fillHeight: true - // Loading symbol - DefaultBusyIndicator { - visible: !details ? false : - details.is_swap && - details.order_status !== "successful" && - details.order_status !== "failed" - Layout.alignment: Qt.AlignHCenter - } + contentWidth: inner_layout.width + contentHeight: inner_layout.height - // Status Text - DefaultText { - Layout.alignment: Qt.AlignHCenter - Layout.topMargin: 20 - font.pixelSize: Style.textSize3 - visible: !details ? false : - details.is_swap || !details.is_maker - color: !details ? "white" : - visible ? getStatusColor(details.order_status) : '' - text_value: API.get().settings_pg.empty_string + (!details ? "" : - visible ? getStatusTextWithPrefix(details.order_status) : '') - } + ColumnLayout { + id: inner_layout + width: root.width - root.padding*2 - 40 // Scrollbar margin - OrderContent { - Layout.topMargin: 25 - Layout.fillWidth: true - Layout.leftMargin: 20 - Layout.rightMargin: Layout.leftMargin - height: 120 - Layout.alignment: Qt.AlignHCenter - details: root.details - in_modal: true - } + // Complete image + DefaultImage { + visible: !details ? false : + details.is_swap && details.order_status === "successful" + Layout.alignment: Qt.AlignHCenter + source: General.image_path + "exchange-trade-complete.svg" + } - HorizontalLine { - Layout.fillWidth: true - Layout.bottomMargin: 20 - color: Style.colorWhite8 - } + // Loading symbol + DefaultBusyIndicator { + visible: !details ? false : + details.is_swap && + details.order_status !== "successful" && + details.order_status !== "failed" + Layout.alignment: Qt.AlignHCenter + } - // Maker/Taker - DefaultText { - text_value: API.get().settings_pg.empty_string + (!details ? "" : - details.is_maker ? qsTr("Maker Order"): qsTr("Taker Order")) - color: Style.colorThemeDarkLight - Layout.alignment: Qt.AlignRight - } + // Status Text + DefaultText { + Layout.alignment: Qt.AlignHCenter + Layout.topMargin: 20 + font.pixelSize: Style.textSize3 + visible: !details ? false : + details.is_swap || !details.is_maker + color: !details ? "white" : + visible ? getStatusColor(details.order_status) : '' + text_value: API.get().settings_pg.empty_string + (!details ? "" : + visible ? getStatusTextWithPrefix(details.order_status) : '') + } - // Refund state - TextFieldWithTitle { - Layout.topMargin: -20 + OrderContent { + Layout.topMargin: 25 + Layout.fillWidth: true + Layout.leftMargin: 20 + Layout.rightMargin: Layout.leftMargin + height: 120 + Layout.alignment: Qt.AlignHCenter + details: root.details + in_modal: true + } - title: API.get().settings_pg.empty_string + (qsTr("Refund State")) - field.text: !details ? "" : - details.order_status === "refunding" ? qsTr("Your swap failed but the auto-refund process for your payment started already. Please wait and keep application opened until you receive your payment back") : "" - field.readOnly: true + HorizontalLine { + Layout.fillWidth: true + Layout.bottomMargin: 20 + color: Style.colorWhite8 + } - visible: field.text !== '' - } + // Maker/Taker + DefaultText { + text_value: API.get().settings_pg.empty_string + (!details ? "" : + details.is_maker ? qsTr("Maker Order"): qsTr("Taker Order")) + color: Style.colorThemeDarkLight + Layout.alignment: Qt.AlignRight + } - // Date - TextWithTitle { - title: API.get().settings_pg.empty_string + (qsTr("Date")) - text: API.get().settings_pg.empty_string + (!details ? "" : - details.date) - visible: text !== '' - } + // Refund state + TextFieldWithTitle { + Layout.topMargin: -20 - // ID - TextWithTitle { - title: API.get().settings_pg.empty_string + (qsTr("ID")) - text: API.get().settings_pg.empty_string + (!details ? "" : - details.order_id) - visible: text !== '' - privacy: true - } + title: API.get().settings_pg.empty_string + (qsTr("Refund State")) + field.text: !details ? "" : + details.order_status === "refunding" ? qsTr("Your swap failed but the auto-refund process for your payment started already. Please wait and keep application opened until you receive your payment back") : "" + field.readOnly: true - // Payment ID - TextWithTitle { - title: API.get().settings_pg.empty_string + (!details ? "" : - details.is_maker ? qsTr("Maker Payment Sent ID") : qsTr("Maker Payment Spent ID")) - text: API.get().settings_pg.empty_string + (!details ? "" : - details.maker_payment_id) - visible: text !== '' - privacy: true - } + visible: field.text !== '' + } - // Payment ID - TextWithTitle { - title: API.get().settings_pg.empty_string + (!details ? "" : - details.is_maker ? qsTr("Taker Payment Spent ID") : qsTr("Taker Payment Sent ID")) - text: API.get().settings_pg.empty_string + (!details ? "" : - details.taker_payment_id) - visible: text !== '' - privacy: true - } + // Date + TextWithTitle { + title: API.get().settings_pg.empty_string + (qsTr("Date")) + text: API.get().settings_pg.empty_string + (!details ? "" : + details.date) + visible: text !== '' + } - // Error ID - TextWithTitle { - title: API.get().settings_pg.empty_string + (qsTr("Error ID")) - text: API.get().settings_pg.empty_string + (!details ? "" : - details.order_error_state) - visible: text !== '' - } + // ID + TextWithTitle { + title: API.get().settings_pg.empty_string + (qsTr("ID")) + text: API.get().settings_pg.empty_string + (!details ? "" : + details.order_id) + visible: text !== '' + privacy: true + } - // Error Details - TextFieldWithTitle { - title: API.get().settings_pg.empty_string + (qsTr("Error Log")) - field.text: API.get().settings_pg.empty_string + (!details ? "" : - details.order_error_message) - field.readOnly: true - copyable: true + // Payment ID + TextWithTitle { + title: API.get().settings_pg.empty_string + (!details ? "" : + details.is_maker ? qsTr("Maker Payment Sent ID") : qsTr("Maker Payment Spent ID")) + text: API.get().settings_pg.empty_string + (!details ? "" : + details.maker_payment_id) + visible: text !== '' + privacy: true + } + + // Payment ID + TextWithTitle { + title: API.get().settings_pg.empty_string + (!details ? "" : + details.is_maker ? qsTr("Taker Payment Spent ID") : qsTr("Taker Payment Sent ID")) + text: API.get().settings_pg.empty_string + (!details ? "" : + details.taker_payment_id) + visible: text !== '' + privacy: true + } + + // Error ID + TextWithTitle { + title: API.get().settings_pg.empty_string + (qsTr("Error ID")) + text: API.get().settings_pg.empty_string + (!details ? "" : + details.order_error_state) + visible: text !== '' + } + + // Error Details + TextFieldWithTitle { + title: API.get().settings_pg.empty_string + (qsTr("Error Log")) + field.text: API.get().settings_pg.empty_string + (!details ? "" : + details.order_error_message) + field.readOnly: true + copyable: true - visible: field.text !== '' + visible: field.text !== '' + } + } } // Buttons From 3121386a956c96c40eefdc002369a59bd95cf354 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Thu, 13 Aug 2020 17:32:38 +0200 Subject: [PATCH 297/515] feat(swap_progress): remove time difference backend, can do it better in the frontend on the fly --- src/atomic.dex.mm2.api.cpp | 11 ++++++----- src/atomic.dex.mm2.cpp | 5 ++--- src/atomic.dex.qt.utilities.cpp | 1 + 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/atomic.dex.mm2.api.cpp b/src/atomic.dex.mm2.api.cpp index 0fefb51c66..e807754563 100644 --- a/src/atomic.dex.mm2.api.cpp +++ b/src/atomic.dex.mm2.api.cpp @@ -743,11 +743,12 @@ namespace mm2::api contents.my_info["my_amount"] = adjust_precision(contents.my_info["my_amount"].get()); } } - using t_event_timestamp_registry = std::unordered_map; - t_event_timestamp_registry event_timestamp_registry; - double total_time_in_seconds = 0.00; - for (auto&& content: j.at("events")) + //using t_event_timestamp_registry = std::unordered_map; + //t_event_timestamp_registry event_timestamp_registry; + //double total_time_in_seconds = 0.00; + + /*for (auto&& content: j.at("events")) { const nlohmann::json& j_evt = content.at("event"); auto timestamp = content.at("timestamp").get(); @@ -863,7 +864,7 @@ namespace mm2::api } std::stringstream ss; ss << std::fixed << std::setprecision(3) << total_time_in_seconds; - contents.total_time_in_seconds = ss.str() + "s"; + contents.total_time_in_seconds = ss.str() + "s";*/ } void diff --git a/src/atomic.dex.mm2.cpp b/src/atomic.dex.mm2.cpp index a6e41a0e9c..361a8dff01 100644 --- a/src/atomic.dex.mm2.cpp +++ b/src/atomic.dex.mm2.cpp @@ -735,9 +735,8 @@ namespace atomic_dex auto swaps = get_swaps(); for (auto &&swap : swaps.swaps) { - for (auto&& event : swap.events) { - std::cout << event << std::endl; - } + spdlog::trace("{}", swap.events.dump(4)); + } }*/ } diff --git a/src/atomic.dex.qt.utilities.cpp b/src/atomic.dex.qt.utilities.cpp index f0fd78b368..409950eb33 100644 --- a/src/atomic.dex.qt.utilities.cpp +++ b/src/atomic.dex.qt.utilities.cpp @@ -15,6 +15,7 @@ ******************************************************************************/ //! QT Headers +#include #include //! Project headers From 277ca1cc22fbef8c23b64916d23c24621e93b6e1 Mon Sep 17 00:00:00 2001 From: naezith Date: Thu, 13 Aug 2020 18:34:14 +0300 Subject: [PATCH 298/515] feat(gui): add dummy SwapProgress.qml --- atomic_qt_design/qml/Exchange/OrderModal.qml | 14 ++++++++++++- .../qml/Exchange/SwapProgress.qml | 20 +++++++++++++++++++ qml.qrc | 1 + 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 atomic_qt_design/qml/Exchange/SwapProgress.qml diff --git a/atomic_qt_design/qml/Exchange/OrderModal.qml b/atomic_qt_design/qml/Exchange/OrderModal.qml index a8436eb574..2d7efb17d6 100644 --- a/atomic_qt_design/qml/Exchange/OrderModal.qml +++ b/atomic_qt_design/qml/Exchange/OrderModal.qml @@ -37,7 +37,7 @@ DefaultModal { ColumnLayout { id: inner_layout - width: root.width - root.padding*2 - 40 // Scrollbar margin + width: root.width - root.padding*2 - 20 // Scrollbar margin // Complete image DefaultImage { @@ -161,6 +161,18 @@ DefaultModal { visible: field.text !== '' } + + HorizontalLine { + Layout.fillWidth: true + Layout.topMargin: 10 + Layout.bottomMargin: Layout.topMargin + color: Style.colorWhite8 + } + + SwapProgress { + Layout.fillWidth: true + details: root.details + } } } diff --git a/atomic_qt_design/qml/Exchange/SwapProgress.qml b/atomic_qt_design/qml/Exchange/SwapProgress.qml new file mode 100644 index 0000000000..f31d7f8087 --- /dev/null +++ b/atomic_qt_design/qml/Exchange/SwapProgress.qml @@ -0,0 +1,20 @@ +import QtQuick 2.14 +import QtQuick.Layouts 1.12 +import QtQuick.Controls 2.12 + +import "../Components" +import "../Constants" + +// Content +ColumnLayout { + property var details + + // Title + DefaultText { + text_value: API.get().settings_pg.empty_string + (qsTr("Swap Progress")) + } + + DefaultText { + text_value: API.get().settings_pg.empty_string + (qsTr("Events: ") + (!details ? 0 : details.events.length)) + } +} diff --git a/qml.qrc b/qml.qrc index 2d9cd2fc3e..b668154b23 100644 --- a/qml.qrc +++ b/qml.qrc @@ -120,6 +120,7 @@ atomic_qt_design/qml/Exchange/Exchange.qml atomic_qt_design/qml/Exchange/ExchangeTab.qml atomic_qt_design/qml/Exchange/OrderLine.qml + atomic_qt_design/qml/Exchange/SwapProgress.qml atomic_qt_design/qml/Exchange/OrderModal.qml atomic_qt_design/qml/Exchange/OrderContent.qml atomic_qt_design/qml/Sidebar/Sidebar.qml From c8c2fc1b1e7082d0b39183809e00bc34360b8bf3 Mon Sep 17 00:00:00 2001 From: naezith Date: Thu, 13 Aug 2020 21:12:46 +0300 Subject: [PATCH 299/515] feat(gui): fix crash at quick click at dex --- atomic_qt_design/qml/Screens/InitialLoading.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/Screens/InitialLoading.qml b/atomic_qt_design/qml/Screens/InitialLoading.qml index e9c9fb9db4..db33e4cb5b 100644 --- a/atomic_qt_design/qml/Screens/InitialLoading.qml +++ b/atomic_qt_design/qml/Screens/InitialLoading.qml @@ -16,7 +16,7 @@ SetupPage { interval: 64 repeat: true onTriggered: { - if(API.get().initial_loading_status === "complete") { + if(API.get().initial_loading_status === "complete" && API.get().portfolio_mdl.length >= 2) { running = false onLoaded() } @@ -43,7 +43,7 @@ SetupPage { DefaultText { text_value: API.get().settings_pg.empty_string + ((API.get().initial_loading_status === "initializing_mm2" ? qsTr("Initializing MM2") : API.get().initial_loading_status === "enabling_coins" ? qsTr("Enabling coins") : - API.get().initial_loading_status === "complete" ? qsTr("Complete") : "") + "...") + API.get().initial_loading_status === "complete" && API.get().portfolio_mdl.length >= 2 ? qsTr("Complete") : qsTr("Getting ready")) + "...") } } } From 5445a0ab40e6cc5ead1b4c3a9d5774f695679216 Mon Sep 17 00:00:00 2001 From: naezith Date: Thu, 13 Aug 2020 21:13:29 +0300 Subject: [PATCH 300/515] feat(gui): remove portfolio loading indicator --- atomic_qt_design/qml/Portfolio/Portfolio.qml | 24 -------------------- 1 file changed, 24 deletions(-) diff --git a/atomic_qt_design/qml/Portfolio/Portfolio.qml b/atomic_qt_design/qml/Portfolio/Portfolio.qml index 64c4ddeaa0..c6245e595b 100644 --- a/atomic_qt_design/qml/Portfolio/Portfolio.qml +++ b/atomic_qt_design/qml/Portfolio/Portfolio.qml @@ -217,33 +217,9 @@ ColumnLayout { } } - // Transactions or loading - Item { - id: loading - visible: API.get().portfolio_mdl.length === 0 - Layout.alignment: Qt.AlignCenter - Layout.fillWidth: true - Layout.fillHeight: true - - ColumnLayout { - anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: parent.verticalCenter - DefaultText { - text_value: API.get().settings_pg.empty_string + (qsTr("Loading")) - Layout.alignment: Qt.AlignHCenter - font.pixelSize: Style.textSize2 - } - - DefaultBusyIndicator { - Layout.alignment: Qt.AlignHCenter - } - } - } - // List DefaultListView { id: list - visible: API.get().portfolio_mdl.length > 0 Layout.alignment: Qt.AlignTop Layout.fillWidth: true Layout.fillHeight: true From 3939d9d3687260eac1683c67d04d70365f0a86b0 Mon Sep 17 00:00:00 2001 From: naezith Date: Thu, 13 Aug 2020 21:56:44 +0300 Subject: [PATCH 301/515] feat(gui): start adding the swap progress list --- .../qml/Exchange/SwapProgress.qml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/atomic_qt_design/qml/Exchange/SwapProgress.qml b/atomic_qt_design/qml/Exchange/SwapProgress.qml index f31d7f8087..e495997a9a 100644 --- a/atomic_qt_design/qml/Exchange/SwapProgress.qml +++ b/atomic_qt_design/qml/Exchange/SwapProgress.qml @@ -7,6 +7,8 @@ import "../Constants" // Content ColumnLayout { + id: root + property var details // Title @@ -17,4 +19,21 @@ ColumnLayout { DefaultText { text_value: API.get().settings_pg.empty_string + (qsTr("Events: ") + (!details ? 0 : details.events.length)) } + + DefaultListView { + Layout.fillWidth: true + Layout.fillHeight: true + model: details ? details.events : [] + + delegate: ColumnLayout { + width: root.width + DefaultText { + id: name + font.pixelSize: price_value.font.pixelSize + + text_value: API.get().settings_pg.empty_string + (modelData.state) + color: Style.colorWhite4 + } + } + } } From 9f502407fcbf57388141cebea5b6dee3033e91ae Mon Sep 17 00:00:00 2001 From: naezith Date: Thu, 13 Aug 2020 23:04:23 +0300 Subject: [PATCH 302/515] Revert "feat(swap_progress): remove time difference backend, can do it better in the frontend on the fly" This reverts commit 3121386a956c96c40eefdc002369a59bd95cf354. --- src/atomic.dex.mm2.api.cpp | 11 +++++------ src/atomic.dex.mm2.cpp | 5 +++-- src/atomic.dex.qt.utilities.cpp | 1 - 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/atomic.dex.mm2.api.cpp b/src/atomic.dex.mm2.api.cpp index e807754563..0fefb51c66 100644 --- a/src/atomic.dex.mm2.api.cpp +++ b/src/atomic.dex.mm2.api.cpp @@ -743,12 +743,11 @@ namespace mm2::api contents.my_info["my_amount"] = adjust_precision(contents.my_info["my_amount"].get()); } } + using t_event_timestamp_registry = std::unordered_map; + t_event_timestamp_registry event_timestamp_registry; + double total_time_in_seconds = 0.00; - //using t_event_timestamp_registry = std::unordered_map; - //t_event_timestamp_registry event_timestamp_registry; - //double total_time_in_seconds = 0.00; - - /*for (auto&& content: j.at("events")) + for (auto&& content: j.at("events")) { const nlohmann::json& j_evt = content.at("event"); auto timestamp = content.at("timestamp").get(); @@ -864,7 +863,7 @@ namespace mm2::api } std::stringstream ss; ss << std::fixed << std::setprecision(3) << total_time_in_seconds; - contents.total_time_in_seconds = ss.str() + "s";*/ + contents.total_time_in_seconds = ss.str() + "s"; } void diff --git a/src/atomic.dex.mm2.cpp b/src/atomic.dex.mm2.cpp index 361a8dff01..a6e41a0e9c 100644 --- a/src/atomic.dex.mm2.cpp +++ b/src/atomic.dex.mm2.cpp @@ -735,8 +735,9 @@ namespace atomic_dex auto swaps = get_swaps(); for (auto &&swap : swaps.swaps) { - spdlog::trace("{}", swap.events.dump(4)); - + for (auto&& event : swap.events) { + std::cout << event << std::endl; + } } }*/ } diff --git a/src/atomic.dex.qt.utilities.cpp b/src/atomic.dex.qt.utilities.cpp index 409950eb33..f0fd78b368 100644 --- a/src/atomic.dex.qt.utilities.cpp +++ b/src/atomic.dex.qt.utilities.cpp @@ -15,7 +15,6 @@ ******************************************************************************/ //! QT Headers -#include #include //! Project headers From d0e4f69e8d14ff2da7213e89aa17372fff96c080 Mon Sep 17 00:00:00 2001 From: naezith Date: Thu, 13 Aug 2020 23:46:13 +0300 Subject: [PATCH 303/515] feat(gui): use get_expected_events_list --- atomic_qt_design/qml/Exchange/OrderModal.qml | 1 + atomic_qt_design/qml/Exchange/SwapProgress.qml | 10 +++------- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/OrderModal.qml b/atomic_qt_design/qml/Exchange/OrderModal.qml index 2d7efb17d6..2b0bb3e43c 100644 --- a/atomic_qt_design/qml/Exchange/OrderModal.qml +++ b/atomic_qt_design/qml/Exchange/OrderModal.qml @@ -170,6 +170,7 @@ DefaultModal { } SwapProgress { + visible: details Layout.fillWidth: true details: root.details } diff --git a/atomic_qt_design/qml/Exchange/SwapProgress.qml b/atomic_qt_design/qml/Exchange/SwapProgress.qml index e495997a9a..66d774bf49 100644 --- a/atomic_qt_design/qml/Exchange/SwapProgress.qml +++ b/atomic_qt_design/qml/Exchange/SwapProgress.qml @@ -16,22 +16,18 @@ ColumnLayout { text_value: API.get().settings_pg.empty_string + (qsTr("Swap Progress")) } - DefaultText { - text_value: API.get().settings_pg.empty_string + (qsTr("Events: ") + (!details ? 0 : details.events.length)) - } - DefaultListView { Layout.fillWidth: true Layout.fillHeight: true - model: details ? details.events : [] + model: details ? API.get().orders_mdl.get_expected_events_list(details.is_maker) : [] delegate: ColumnLayout { width: root.width DefaultText { id: name - font.pixelSize: price_value.font.pixelSize + font.pixelSize: Style.textSizeSmall4 - text_value: API.get().settings_pg.empty_string + (modelData.state) + text_value: API.get().settings_pg.empty_string + (modelData) color: Style.colorWhite4 } } From 6b6319ddaf912e88a1e9818ad8a6684df0fea3bc Mon Sep 17 00:00:00 2001 From: naezith Date: Fri, 14 Aug 2020 00:48:20 +0300 Subject: [PATCH 304/515] feat(gui): display time spent --- .../qml/Exchange/SwapProgress.qml | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/SwapProgress.qml b/atomic_qt_design/qml/Exchange/SwapProgress.qml index 66d774bf49..c26fa4991d 100644 --- a/atomic_qt_design/qml/Exchange/SwapProgress.qml +++ b/atomic_qt_design/qml/Exchange/SwapProgress.qml @@ -14,21 +14,41 @@ ColumnLayout { // Title DefaultText { text_value: API.get().settings_pg.empty_string + (qsTr("Swap Progress")) + font.pixelSize: Style.textSize1 + font.bold: true } - DefaultListView { + Repeater { Layout.fillWidth: true Layout.fillHeight: true model: details ? API.get().orders_mdl.get_expected_events_list(details.is_maker) : [] delegate: ColumnLayout { + property var event: { + if(!details) return undefined + const idx = details.events.map(e => e.state).indexOf(modelData) + if(idx === -1) return undefined + + return details.events[idx] + } + width: root.width DefaultText { id: name font.pixelSize: Style.textSizeSmall4 text_value: API.get().settings_pg.empty_string + (modelData) - color: Style.colorWhite4 + color: event ? Style.colorText : Style.colorTextDisabled + } + + DefaultText { + visible: event + font.pixelSize: Style.textSizeSmall2 + + text_value: API.get().settings_pg.empty_string + (event ? qsTr("Took %1s", "SECONDS").arg(General.formatDouble((event.timestamp - event.started_at)/1000, 1)) : '') + color: Style.colorGreen + + Layout.bottomMargin: 10 } } } From 97f426408c23cf950b61e6e81a73d0d318ac7834 Mon Sep 17 00:00:00 2001 From: naezith Date: Fri, 14 Aug 2020 02:13:12 +0300 Subject: [PATCH 305/515] feat(gui): timeline and seconds passed info --- .../qml/Exchange/SwapProgress.qml | 37 +++++++++++++++++-- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/SwapProgress.qml b/atomic_qt_design/qml/Exchange/SwapProgress.qml index c26fa4991d..4284f69e82 100644 --- a/atomic_qt_design/qml/Exchange/SwapProgress.qml +++ b/atomic_qt_design/qml/Exchange/SwapProgress.qml @@ -10,12 +10,19 @@ ColumnLayout { id: root property var details + readonly property double total_time_passed: { + if(!details) return 0 + const events = details.events + if(events.length === 0) return 0 + + return (events[events.length-1].timestamp - events[0].started_at*1000) / 1000 + } // Title DefaultText { - text_value: API.get().settings_pg.empty_string + (qsTr("Swap Progress")) + text_value: API.get().settings_pg.empty_string + (qsTr("Swap Progress") + " | " + + qsTr("%1 seconds", "SECONDS").arg(General.formatDouble(total_time_passed, 1))) font.pixelSize: Style.textSize1 - font.bold: true } Repeater { @@ -24,7 +31,7 @@ ColumnLayout { model: details ? API.get().orders_mdl.get_expected_events_list(details.is_maker) : [] delegate: ColumnLayout { - property var event: { + readonly property var event: { if(!details) return undefined const idx = details.events.map(e => e.state).indexOf(modelData) if(idx === -1) return undefined @@ -32,7 +39,16 @@ ColumnLayout { return details.events[idx] } + readonly property double seconds_passed: { + if(!event) return 0 + + let start = event.started_at + if(index === 0) start *= 1000 + return (event.timestamp - start)/1000 + } + width: root.width + DefaultText { id: name font.pixelSize: Style.textSizeSmall4 @@ -41,11 +57,24 @@ ColumnLayout { color: event ? Style.colorText : Style.colorTextDisabled } + Rectangle { + width: 300 + height: 2 + + color: Style.colorWhite8 + + Rectangle { + width: parent.width * (total_time_passed > 0 ? (seconds_passed / total_time_passed) : 0) + height: parent.height + color: Style.colorGreen + } + } + DefaultText { visible: event font.pixelSize: Style.textSizeSmall2 - text_value: API.get().settings_pg.empty_string + (event ? qsTr("Took %1s", "SECONDS").arg(General.formatDouble((event.timestamp - event.started_at)/1000, 1)) : '') + text_value: API.get().settings_pg.empty_string + (event ? qsTr("Took %1s", "SECONDS").arg(General.formatDouble(seconds_passed, 1)) : '') color: Style.colorGreen Layout.bottomMargin: 10 From 3fd1ba2d53f815e83f3ace6fa020445896685909 Mon Sep 17 00:00:00 2001 From: naezith Date: Fri, 14 Aug 2020 03:12:23 +0300 Subject: [PATCH 306/515] feat(gui): add status circle --- .../qml/Exchange/SwapProgress.qml | 58 +++++++++++++------ 1 file changed, 39 insertions(+), 19 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/SwapProgress.qml b/atomic_qt_design/qml/Exchange/SwapProgress.qml index 4284f69e82..d2d9d22d0b 100644 --- a/atomic_qt_design/qml/Exchange/SwapProgress.qml +++ b/atomic_qt_design/qml/Exchange/SwapProgress.qml @@ -30,7 +30,7 @@ ColumnLayout { Layout.fillHeight: true model: details ? API.get().orders_mdl.get_expected_events_list(details.is_maker) : [] - delegate: ColumnLayout { + delegate: Item { readonly property var event: { if(!details) return undefined const idx = details.events.map(e => e.state).indexOf(modelData) @@ -48,36 +48,56 @@ ColumnLayout { } width: root.width + height: 50 DefaultText { - id: name - font.pixelSize: Style.textSizeSmall4 + id: icon - text_value: API.get().settings_pg.empty_string + (modelData) - color: event ? Style.colorText : Style.colorTextDisabled + text_value: event ? "●" : "○" // ◍ for unfinished one ●◍○ + anchors.left: parent.left + anchors.leftMargin: 10 + anchors.verticalCenter: parent.verticalCenter + color: event ? Style.colorGreen : Style.colorTextDisabled // Orange for unfinished one } - Rectangle { - width: 300 - height: 2 + ColumnLayout { + id: col_layout - color: Style.colorWhite8 + anchors.left: icon.right + anchors.leftMargin: icon.anchors.leftMargin + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + + DefaultText { + id: name + font.pixelSize: Style.textSizeSmall4 + + text_value: API.get().settings_pg.empty_string + (modelData) + color: event ? Style.colorText : Style.colorTextDisabled + } Rectangle { - width: parent.width * (total_time_passed > 0 ? (seconds_passed / total_time_passed) : 0) - height: parent.height - color: Style.colorGreen + width: 300 + height: 2 + + color: Style.colorWhite8 + + Rectangle { + width: parent.width * (total_time_passed > 0 ? (seconds_passed / total_time_passed) : 0) + height: parent.height + color: Style.colorGreen + } } - } - DefaultText { - visible: event - font.pixelSize: Style.textSizeSmall2 + DefaultText { + visible: event + font.pixelSize: Style.textSizeSmall2 - text_value: API.get().settings_pg.empty_string + (event ? qsTr("Took %1s", "SECONDS").arg(General.formatDouble(seconds_passed, 1)) : '') - color: Style.colorGreen + text_value: API.get().settings_pg.empty_string + (event ? qsTr("Took %1s", "SECONDS").arg(General.formatDouble(seconds_passed, 1)) : '') + color: Style.colorGreen - Layout.bottomMargin: 10 + Layout.bottomMargin: 10 + } } } } From ca32f471a2a9b087cba531a7507b395c139c85fb Mon Sep 17 00:00:00 2001 From: naezith Date: Fri, 14 Aug 2020 03:39:22 +0300 Subject: [PATCH 307/515] feat(gui): event pending status --- atomic_qt_design/qml/Exchange/OrderModal.qml | 2 +- .../qml/Exchange/SwapProgress.qml | 30 +++++++++++++++---- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/OrderModal.qml b/atomic_qt_design/qml/Exchange/OrderModal.qml index 2b0bb3e43c..7018bb7ab6 100644 --- a/atomic_qt_design/qml/Exchange/OrderModal.qml +++ b/atomic_qt_design/qml/Exchange/OrderModal.qml @@ -170,7 +170,7 @@ DefaultModal { } SwapProgress { - visible: details + visible: details !== undefined Layout.fillWidth: true details: root.details } diff --git a/atomic_qt_design/qml/Exchange/SwapProgress.qml b/atomic_qt_design/qml/Exchange/SwapProgress.qml index d2d9d22d0b..d8da76bff3 100644 --- a/atomic_qt_design/qml/Exchange/SwapProgress.qml +++ b/atomic_qt_design/qml/Exchange/SwapProgress.qml @@ -9,6 +9,7 @@ import "../Constants" ColumnLayout { id: root + property var all_events: details ? API.get().orders_mdl.get_expected_events_list(details.is_maker) : [] property var details readonly property double total_time_passed: { if(!details) return 0 @@ -18,6 +19,18 @@ ColumnLayout { return (events[events.length-1].timestamp - events[0].started_at*1000) / 1000 } + readonly property int current_event_idx: { + if(!details) return -1 + const events = details.events + if(events.length === 0) return -1 + if(all_events.length === 0) return -1 + + const idx = all_events.indexOf(events[events.length-1].state) + if(idx === -1) return -1 + + return idx + 1 + } + // Title DefaultText { text_value: API.get().settings_pg.empty_string + (qsTr("Swap Progress") + " | " + @@ -28,7 +41,7 @@ ColumnLayout { Repeater { Layout.fillWidth: true Layout.fillHeight: true - model: details ? API.get().orders_mdl.get_expected_events_list(details.is_maker) : [] + model: all_events delegate: Item { readonly property var event: { @@ -41,23 +54,28 @@ ColumnLayout { readonly property double seconds_passed: { if(!event) return 0 + if(!event.started_at) return 0 + if(!event.timestamp) return 0 let start = event.started_at if(index === 0) start *= 1000 + return (event.timestamp - start)/1000 } + readonly property bool is_current_event: index === current_event_idx + width: root.width height: 50 DefaultText { id: icon - text_value: event ? "●" : "○" // ◍ for unfinished one ●◍○ + text_value: event || is_current_event ? "●" : "○" anchors.left: parent.left anchors.leftMargin: 10 anchors.verticalCenter: parent.verticalCenter - color: event ? Style.colorGreen : Style.colorTextDisabled // Orange for unfinished one + color: event ? Style.colorGreen : is_current_event ? Style.colorOrange : Style.colorTextDisabled } ColumnLayout { @@ -73,10 +91,12 @@ ColumnLayout { font.pixelSize: Style.textSizeSmall4 text_value: API.get().settings_pg.empty_string + (modelData) - color: event ? Style.colorText : Style.colorTextDisabled + color: event || is_current_event ? Style.colorText : Style.colorTextDisabled } Rectangle { + id: bar + visible: event ? true : false width: 300 height: 2 @@ -90,7 +110,7 @@ ColumnLayout { } DefaultText { - visible: event + visible: bar.visible font.pixelSize: Style.textSizeSmall2 text_value: API.get().settings_pg.empty_string + (event ? qsTr("Took %1s", "SECONDS").arg(General.formatDouble(seconds_passed, 1)) : '') From cc403431d78ef47902f1bc7c4b4929dee531e7a4 Mon Sep 17 00:00:00 2001 From: naezith Date: Fri, 14 Aug 2020 04:06:50 +0300 Subject: [PATCH 308/515] feat(gui): polish colors and positioning --- atomic_qt_design/qml/Exchange/SwapProgress.qml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/SwapProgress.qml b/atomic_qt_design/qml/Exchange/SwapProgress.qml index d8da76bff3..5b56d40ba5 100644 --- a/atomic_qt_design/qml/Exchange/SwapProgress.qml +++ b/atomic_qt_design/qml/Exchange/SwapProgress.qml @@ -33,9 +33,10 @@ ColumnLayout { // Title DefaultText { - text_value: API.get().settings_pg.empty_string + (qsTr("Swap Progress") + " | " + + text_value: API.get().settings_pg.empty_string + (qsTr("Progress details") + " | " + qsTr("%1 seconds", "SECONDS").arg(General.formatDouble(total_time_passed, 1))) font.pixelSize: Style.textSize1 + Layout.bottomMargin: 10 } Repeater { @@ -74,7 +75,7 @@ ColumnLayout { text_value: event || is_current_event ? "●" : "○" anchors.left: parent.left anchors.leftMargin: 10 - anchors.verticalCenter: parent.verticalCenter + anchors.verticalCenter: col_layout.verticalCenter color: event ? Style.colorGreen : is_current_event ? Style.colorOrange : Style.colorTextDisabled } @@ -88,10 +89,11 @@ ColumnLayout { DefaultText { id: name + font.pixelSize: Style.textSizeSmall4 text_value: API.get().settings_pg.empty_string + (modelData) - color: event || is_current_event ? Style.colorText : Style.colorTextDisabled + color: event ? Style.colorText : is_current_event ? Style.colorText2 : Style.colorTextDisabled } Rectangle { @@ -115,8 +117,6 @@ ColumnLayout { text_value: API.get().settings_pg.empty_string + (event ? qsTr("Took %1s", "SECONDS").arg(General.formatDouble(seconds_passed, 1)) : '') color: Style.colorGreen - - Layout.bottomMargin: 10 } } } From 2b41939b5c3dcd7c57bdbb201bb5f255588b439b Mon Sep 17 00:00:00 2001 From: romanszterg Date: Sat, 15 Aug 2020 11:14:16 +0200 Subject: [PATCH 309/515] feat(max_taker_vol): add QML connection for max_taker_vol --- src/atomic.dex.qt.trading.page.cpp | 20 ++++++++++++++++++-- src/atomic.dex.qt.trading.page.hpp | 1 + 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/atomic.dex.qt.trading.page.cpp b/src/atomic.dex.qt.trading.page.cpp index 69cd01cdd2..d81c79015e 100644 --- a/src/atomic.dex.qt.trading.page.cpp +++ b/src/atomic.dex.qt.trading.page.cpp @@ -69,12 +69,28 @@ namespace atomic_dex //! Public QML API namespace atomic_dex { + QVariant + trading_page::get_max_taker_vol(const QString& ticker) const noexcept + { + ::mm2::api::max_taker_vol_request req{.coin = ticker.toStdString()}; + auto answer = ::mm2::api::rpc_max_taker_vol(std::move(req)); + if (answer.result.has_value()) + { + QJsonObject out{ + {"denom", QString::fromStdString(answer.result.value().denom)}, + {"numer", QString::fromStdString(answer.result.value().numer)}, + }; + return out; + } + return {}; + } + QVariant trading_page::get_raw_mm2_coin_cfg(const QString& ticker) const noexcept { - QVariant out; + QVariant out; nlohmann::json j = m_system_manager.get_system().get_raw_mm2_ticker_cfg(ticker.toStdString()); - out = nlohmann_json_object_to_qt_json_object(j); + out = nlohmann_json_object_to_qt_json_object(j); return out; } diff --git a/src/atomic.dex.qt.trading.page.hpp b/src/atomic.dex.qt.trading.page.hpp index c3c0c61213..b8b0bd7836 100644 --- a/src/atomic.dex.qt.trading.page.hpp +++ b/src/atomic.dex.qt.trading.page.hpp @@ -106,6 +106,7 @@ namespace atomic_dex const QString& price_numer, const QString& rel_nota = "", const QString& rel_confs = ""); Q_INVOKABLE void swap_market_pair(); Q_INVOKABLE QVariant get_raw_mm2_coin_cfg(const QString& ticker) const noexcept; + Q_INVOKABLE QVariant get_max_taker_vol(const QString& ticker) const noexcept; //! Properties [[nodiscard]] qt_orderbook_wrapper* get_orderbook_wrapper() const noexcept; From d9249adf0e5ebc4dba89a110b9cc7eb9d7a36606 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Sat, 15 Aug 2020 12:39:09 +0200 Subject: [PATCH 310/515] feat(tx/claiming): 24Hour time format --- src/atomic.dex.mm2.api.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/atomic.dex.mm2.api.cpp b/src/atomic.dex.mm2.api.cpp index 0fefb51c66..64aedea98d 100644 --- a/src/atomic.dex.mm2.api.cpp +++ b/src/atomic.dex.mm2.api.cpp @@ -220,7 +220,7 @@ namespace mm2::api j.at("tx_hash").get_to(cfg.tx_hash); j.at("tx_hex").get_to(cfg.tx_hex); - std::string s = to_human_date(cfg.timestamp, "%e %b %Y, %I:%M"); + std::string s = to_human_date(cfg.timestamp, "%e %b %Y, %H:%M"); cfg.timestamp_as_date = std::move(s); } @@ -1121,19 +1121,19 @@ namespace mm2::api if (obj.contains("accrue_start_at")) { auto accrue_timestamp = obj.at("accrue_start_at").get(); - obj["accrue_start_at_human_date"] = to_human_date(accrue_timestamp, "%e %b %Y, %I:%M"); + obj["accrue_start_at_human_date"] = to_human_date(accrue_timestamp, "%e %b %Y, %H:%M"); } if (obj.contains("accrue_stop_at")) { auto accrue_timestamp = obj.at("accrue_stop_at").get(); - obj["accrue_stop_at_human_date"] = to_human_date(accrue_timestamp, "%e %b %Y, %I:%M"); + obj["accrue_stop_at_human_date"] = to_human_date(accrue_timestamp, "%e %b %Y, %H:%M"); } if (obj.contains("locktime")) { auto locktime_timestamp = obj.at("locktime").get(); - obj["locktime_human_date"] = to_human_date(locktime_timestamp, "%e %b %Y, %I:%M"); + obj["locktime_human_date"] = to_human_date(locktime_timestamp, "%e %b %Y, %H:%M"); } } } From f1006542b2d96c12ca9ae53d7ba57fd6274a94e5 Mon Sep 17 00:00:00 2001 From: naezith Date: Sat, 15 Aug 2020 14:01:09 +0300 Subject: [PATCH 311/515] feat(gui): show current events if swap failed --- atomic_qt_design/qml/Exchange/SwapProgress.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomic_qt_design/qml/Exchange/SwapProgress.qml b/atomic_qt_design/qml/Exchange/SwapProgress.qml index 5b56d40ba5..b3fd7c597f 100644 --- a/atomic_qt_design/qml/Exchange/SwapProgress.qml +++ b/atomic_qt_design/qml/Exchange/SwapProgress.qml @@ -9,7 +9,7 @@ import "../Constants" ColumnLayout { id: root - property var all_events: details ? API.get().orders_mdl.get_expected_events_list(details.is_maker) : [] + property var all_events: !details ? [] : details.order_status === "failed" ? details.events.map(e => e.state) : API.get().orders_mdl.get_expected_events_list(details.is_maker) property var details readonly property double total_time_passed: { if(!details) return 0 From 1336f06c719cbef153e8df43cd7e03af4724e10b Mon Sep 17 00:00:00 2001 From: naezith Date: Sat, 15 Aug 2020 14:05:07 +0300 Subject: [PATCH 312/515] feat(gui): hide swap progress for maker orders --- atomic_qt_design/qml/Exchange/OrderModal.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomic_qt_design/qml/Exchange/OrderModal.qml b/atomic_qt_design/qml/Exchange/OrderModal.qml index 7018bb7ab6..57dd264371 100644 --- a/atomic_qt_design/qml/Exchange/OrderModal.qml +++ b/atomic_qt_design/qml/Exchange/OrderModal.qml @@ -170,7 +170,7 @@ DefaultModal { } SwapProgress { - visible: details !== undefined + visible: details !== undefined && !details.is_maker Layout.fillWidth: true details: root.details } From 96d054be9a62b3df7c2dcdbacc4ef477d9721b7e Mon Sep 17 00:00:00 2001 From: romanszterg Date: Sat, 15 Aug 2020 13:11:29 +0200 Subject: [PATCH 313/515] feat(swap_details_progress): add success and error events --- src/atomic.dex.qt.orders.data.hpp | 6 ++++++ src/atomic.dex.qt.orders.model.cpp | 16 ++++++++++++++-- src/atomic.dex.qt.orders.model.hpp | 4 +++- src/atomic.dex.qt.utilities.cpp | 9 +++++++++ src/atomic.dex.qt.utilities.hpp | 1 + 5 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/atomic.dex.qt.orders.data.hpp b/src/atomic.dex.qt.orders.data.hpp index 864f25c112..5d837952d2 100644 --- a/src/atomic.dex.qt.orders.data.hpp +++ b/src/atomic.dex.qt.orders.data.hpp @@ -61,5 +61,11 @@ namespace atomic_dex //! Events QJsonArray events; + + //! error events + QStringList error_events; + + //! success events + QStringList success_events; }; } // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.orders.model.cpp b/src/atomic.dex.qt.orders.model.cpp index 85b8846a49..c06057a8d8 100644 --- a/src/atomic.dex.qt.orders.model.cpp +++ b/src/atomic.dex.qt.orders.model.cpp @@ -148,6 +148,10 @@ namespace atomic_dex item.order_error_message = value.toString(); case EventsRole: item.events = value.toJsonArray(); + case SuccessEventsRole: + item.success_events = value.toStringList(); + case ErrorEventsRole: + item.error_events = value.toStringList(); } emit dataChanged(index, index, {role}); @@ -203,6 +207,10 @@ namespace atomic_dex return item.order_error_message; case EventsRole: return item.events; + case SuccessEventsRole: + return item.success_events; + case ErrorEventsRole: + return item.error_events; } return {}; } @@ -314,7 +322,9 @@ namespace atomic_dex .is_swap = true, .is_cancellable = false, .is_recoverable = contents.funds_recoverable, - .events = nlohmann_json_array_to_qt_json_array(contents.events)}; + .events = nlohmann_json_array_to_qt_json_array(contents.events), + .error_events = vector_std_string_to_qt_string_list(contents.error_events), + .success_events = vector_std_string_to_qt_string_list(contents.success_events)}; data.ticker_pair = data.base_coin + "/" + data.rel_coin; if (data.order_status == "failed") { @@ -521,7 +531,9 @@ namespace atomic_dex {IsRecoverableRole, "recoverable"}, {OrderErrorStateRole, "order_error_state"}, {OrderErrorMessageRole, "order_error_message"}, - {EventsRole, "events"}}; + {EventsRole, "events"}, + {SuccessEventsRole, "success_events"}, + {ErrorEventsRole, "error_events"}}; } int diff --git a/src/atomic.dex.qt.orders.model.hpp b/src/atomic.dex.qt.orders.model.hpp index 9a0621eca4..fbed352e6f 100644 --- a/src/atomic.dex.qt.orders.model.hpp +++ b/src/atomic.dex.qt.orders.model.hpp @@ -57,7 +57,9 @@ namespace atomic_dex IsRecoverableRole, OrderErrorStateRole, OrderErrorMessageRole, - EventsRole + EventsRole, + SuccessEventsRole, + ErrorEventsRole }; diff --git a/src/atomic.dex.qt.utilities.cpp b/src/atomic.dex.qt.utilities.cpp index f0fd78b368..db2aa87f6c 100644 --- a/src/atomic.dex.qt.utilities.cpp +++ b/src/atomic.dex.qt.utilities.cpp @@ -60,4 +60,13 @@ namespace atomic_dex } return change_24h; } + + QStringList + vector_std_string_to_qt_string_list(const std::vector& vec) + { + QStringList out; + out.reserve(vec.size()); + for (auto&& cur: vec) { out.append(QString::fromStdString(cur)); } + return out; + } } // namespace atomic_dex diff --git a/src/atomic.dex.qt.utilities.hpp b/src/atomic.dex.qt.utilities.hpp index 9a5a1bc531..feb1919803 100644 --- a/src/atomic.dex.qt.utilities.hpp +++ b/src/atomic.dex.qt.utilities.hpp @@ -29,6 +29,7 @@ namespace atomic_dex { bool am_i_able_to_reach_this_endpoint(const QString& endpoint); + QStringList vector_std_string_to_qt_string_list(const std::vector& vec); QJsonArray nlohmann_json_array_to_qt_json_array(const nlohmann::json& j); QJsonObject nlohmann_json_object_to_qt_json_object(const nlohmann::json& j); QString retrieve_change_24h(const atomic_dex::coinpaprika_provider& paprika, const atomic_dex::coin_config& coin, const atomic_dex::cfg& config); From 34ae0d7f9a73d11929c2abf25687f2431c1ea992 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Sat, 15 Aug 2020 13:28:17 +0200 Subject: [PATCH 314/515] feat(swap_details_progress): clean code --- src/atomic.dex.mm2.api.hpp | 1 - src/atomic.dex.qt.orders.model.cpp | 36 ------------------------ src/atomic.dex.qt.orders.model.hpp | 2 -- src/atomic.dex.qt.orders.proxy.model.cpp | 6 ++++ 4 files changed, 6 insertions(+), 39 deletions(-) diff --git a/src/atomic.dex.mm2.api.hpp b/src/atomic.dex.mm2.api.hpp index 4834375182..b592671d83 100644 --- a/src/atomic.dex.mm2.api.hpp +++ b/src/atomic.dex.mm2.api.hpp @@ -652,7 +652,6 @@ namespace mm2::api struct swap_contents { - // using t_event_registry = std::unordered_map>; std::vector error_events; std::vector success_events; nlohmann::json events; diff --git a/src/atomic.dex.qt.orders.model.cpp b/src/atomic.dex.qt.orders.model.cpp index c06057a8d8..ca6d0944a8 100644 --- a/src/atomic.dex.qt.orders.model.cpp +++ b/src/atomic.dex.qt.orders.model.cpp @@ -558,40 +558,4 @@ namespace atomic_dex this->m_model_data.clear(); this->endResetModel(); } -} // namespace atomic_dex - -//! Public QML API -namespace atomic_dex -{ - QStringList - orders_model::get_expected_events_list(bool is_maker) const noexcept - { - if (is_maker) - { - return { - "Started", - "Negotiated", - "TakerFeeValidated", - "MakerPaymentSent", - "TakerPaymentReceived", - "TakerPaymentWaitConfirmStarted", - "TakerPaymentValidatedAndConfirmed", - "TakerPaymentSpent", - "Finished"}; - } - else - { - return { - "Started", - "Negotiated", - "TakerFeeSent", - "MakerPaymentReceived", - "MakerPaymentWaitConfirmStarted", - "MakerPaymentValidatedAndConfirmed", - "TakerPaymentSent", - "TakerPaymentSpent", - "MakerPaymentSpent", - "Finished"}; - } - } } // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.orders.model.hpp b/src/atomic.dex.qt.orders.model.hpp index fbed352e6f..584b39a4db 100644 --- a/src/atomic.dex.qt.orders.model.hpp +++ b/src/atomic.dex.qt.orders.model.hpp @@ -80,8 +80,6 @@ namespace atomic_dex [[nodiscard]] int get_length() const noexcept; [[nodiscard]] orders_proxy_model* get_orders_proxy_mdl() const noexcept; - //! QML_API - Q_INVOKABLE QStringList get_expected_events_list(bool is_maker) const noexcept; signals: void lengthChanged(); void ordersProxyChanged(); diff --git a/src/atomic.dex.qt.orders.proxy.model.cpp b/src/atomic.dex.qt.orders.proxy.model.cpp index 88286a63cb..bfcfa39204 100644 --- a/src/atomic.dex.qt.orders.proxy.model.cpp +++ b/src/atomic.dex.qt.orders.proxy.model.cpp @@ -81,6 +81,12 @@ namespace atomic_dex break; case orders_model::OrdersRoles::OrderErrorMessageRole: break; + case orders_model::EventsRole: + break; + case orders_model::SuccessEventsRole: + break; + case orders_model::ErrorEventsRole: + break; } return true; } From ff8964f4c0eb3cd7b276fbf4e548a6a9a676997b Mon Sep 17 00:00:00 2001 From: naezith Date: Sat, 15 Aug 2020 14:29:33 +0300 Subject: [PATCH 315/515] feat(gui): red color for error events --- .../qml/Exchange/SwapProgress.qml | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/SwapProgress.qml b/atomic_qt_design/qml/Exchange/SwapProgress.qml index b3fd7c597f..f8445ff06c 100644 --- a/atomic_qt_design/qml/Exchange/SwapProgress.qml +++ b/atomic_qt_design/qml/Exchange/SwapProgress.qml @@ -9,7 +9,7 @@ import "../Constants" ColumnLayout { id: root - property var all_events: !details ? [] : details.order_status === "failed" ? details.events.map(e => e.state) : API.get().orders_mdl.get_expected_events_list(details.is_maker) + property var all_events: !details ? [] : details.order_status === "failed" ? details.events.map(e => e.state) : details.success_events property var details readonly property double total_time_passed: { if(!details) return 0 @@ -76,7 +76,23 @@ ColumnLayout { anchors.left: parent.left anchors.leftMargin: 10 anchors.verticalCenter: col_layout.verticalCenter - color: event ? Style.colorGreen : is_current_event ? Style.colorOrange : Style.colorTextDisabled + color: { + // Already exists, completed event + if(event) { + // Red for the Finished if swap failed + if(event.state === "Finished" && details.order_status === "failed") return Style.colorRed + + // Red for error event, green for the others + return details.error_events.indexOf(event.state) === -1 ? Style.colorGreen : Style.colorRed + } + + // In progress one is orange + if(is_current_event) + return Style.colorOrange + + // Passive color for the rest + return Style.colorTextDisabled + } } ColumnLayout { From 8b67a037bbccd8616dca93eb451b829a23b2bcbc Mon Sep 17 00:00:00 2001 From: naezith Date: Sat, 15 Aug 2020 14:52:56 +0300 Subject: [PATCH 316/515] feat(gui): calculate total swap time --- atomic_qt_design/qml/Exchange/SwapProgress.qml | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/atomic_qt_design/qml/Exchange/SwapProgress.qml b/atomic_qt_design/qml/Exchange/SwapProgress.qml index f8445ff06c..2d48ec2a54 100644 --- a/atomic_qt_design/qml/Exchange/SwapProgress.qml +++ b/atomic_qt_design/qml/Exchange/SwapProgress.qml @@ -13,10 +13,26 @@ ColumnLayout { property var details readonly property double total_time_passed: { if(!details) return 0 + const events = details.events if(events.length === 0) return 0 - return (events[events.length-1].timestamp - events[0].started_at*1000) / 1000 + let sum = 0 + for(let i = 0; i < events.length; ++i) { + const e = events[i] + let start = e.started_at + let end = e.timestamp + + // Start timestamp of Started is seconds somehow + if(e.state === "Started") + start *= 1000 + + if(start !== undefined && end !== undefined) { + sum += end - start + } + } + + return sum / 1000 } readonly property int current_event_idx: { From 86f2f50d32c21a0a2a49f1e9e167ceb610acf4bf Mon Sep 17 00:00:00 2001 From: naezith Date: Sat, 15 Aug 2020 15:00:24 +0300 Subject: [PATCH 317/515] feat(gui): show real events if swap has an error --- atomic_qt_design/qml/Exchange/SwapProgress.qml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/atomic_qt_design/qml/Exchange/SwapProgress.qml b/atomic_qt_design/qml/Exchange/SwapProgress.qml index 2d48ec2a54..63f300fe2e 100644 --- a/atomic_qt_design/qml/Exchange/SwapProgress.qml +++ b/atomic_qt_design/qml/Exchange/SwapProgress.qml @@ -9,7 +9,19 @@ import "../Constants" ColumnLayout { id: root - property var all_events: !details ? [] : details.order_status === "failed" ? details.events.map(e => e.state) : details.success_events + readonly property bool has_error_event: { + if(!details) return false + + const events = details.events + + for(let i = events.length - 1; i >= 0; --i) + if(details.error_events.indexOf(events[i].state) !== -1) + return true + + return false + } + + readonly property var all_events: !details ? [] : has_error_event ? details.events.map(e => e.state) : details.success_events property var details readonly property double total_time_passed: { if(!details) return 0 From f737eb47c3cd0dfc60916e73adaf5fc01e1e7783 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Sat, 15 Aug 2020 14:17:55 +0200 Subject: [PATCH 318/515] feat(connection): allow connection only if kmd and btc are enabled --- src/atomic.dex.app.cpp | 19 ++++++++++++++++++- src/atomic.dex.app.hpp | 6 ++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index 26a39fa5fa..353b673912 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -421,6 +421,19 @@ namespace atomic_dex { //! This event is called when a call is enabled and cex provider finished fetch datas spdlog::debug("{} l{}", __FUNCTION__, __LINE__); + if (evt.ticker == "BTC") + { + this->m_btc_fully_enabled = true; + } + + if (evt.ticker == "KMD") + { + this->m_kmd_fully_enabled = true; + } + if (this->m_kmd_fully_enabled && this->m_btc_fully_enabled) + { + this->set_status("complete"); + } qobject_cast(m_manager_models.at("portfolio"))->initialize_portfolio(evt.ticker); } @@ -588,7 +601,7 @@ namespace atomic_dex application::on_mm2_started_event([[maybe_unused]] const mm2_started& evt) noexcept { spdlog::debug("{} l{}", __FUNCTION__, __LINE__); - this->set_status("complete"); + // this->set_status("complete"); } void @@ -685,6 +698,10 @@ namespace atomic_dex this->m_wallet_manager.just_set_wallet_name(""); emit onWalletDefaultNameChanged(); + + this->m_btc_fully_enabled = false; + this->m_kmd_fully_enabled = false; + this->set_status("None"); return fs::remove(get_atomic_dex_config_folder() / "default.wallet"); } diff --git a/src/atomic.dex.app.hpp b/src/atomic.dex.app.hpp index 307a34d7ed..ebf6245421 100644 --- a/src/atomic.dex.app.hpp +++ b/src/atomic.dex.app.hpp @@ -108,6 +108,8 @@ namespace atomic_dex current_coin_info* m_coin_info; t_manager_model_registry m_manager_models; t_events_actions m_event_actions{{false}}; + std::atomic_bool m_btc_fully_enabled{false}; + std::atomic_bool m_kmd_fully_enabled{false}; public: //! Constructor @@ -200,8 +202,8 @@ namespace atomic_dex Q_INVOKABLE static QString get_price_amount(const QString& base_amount, const QString& rel_amount); Q_INVOKABLE bool do_i_have_enough_funds(const QString& ticker, const QString& amount) const; Q_INVOKABLE bool disable_coins(const QStringList& coins); - //Q_INVOKABLE bool is_claiming_ready(const QString& ticker); - Q_INVOKABLE QVariant claim_rewards(const QString& ticker); + // Q_INVOKABLE bool is_claiming_ready(const QString& ticker); + Q_INVOKABLE QVariant claim_rewards(const QString& ticker); Q_INVOKABLE QString get_cex_rates(const QString& base, const QString& rel); From a6faa51b0a313eda62a008c7a5763334ddb72f6b Mon Sep 17 00:00:00 2001 From: naezith Date: Sat, 15 Aug 2020 15:45:32 +0300 Subject: [PATCH 319/515] feat(gui): h m s ms kind of durations --- atomic_qt_design/qml/Constants/General.qml | 38 ++++++++++++++++--- .../qml/Exchange/SwapProgress.qml | 4 +- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/atomic_qt_design/qml/Constants/General.qml b/atomic_qt_design/qml/Constants/General.qml index 279c0abbc4..8ce0d611da 100644 --- a/atomic_qt_design/qml/Constants/General.qml +++ b/atomic_qt_design/qml/Constants/General.qml @@ -61,26 +61,52 @@ QtObject { return (new Date(timestamp * 1000)) } - function secondsToTimeLeft(date_now, date_future) { - let delta = Math.abs(date_future - date_now) + function getDuration(total_seconds) { + let delta = Math.abs(total_seconds) let days = Math.floor(delta / 86400) delta -= days * 86400 let hours = Math.floor(delta / 3600) % 24 delta -= hours * 3600 - if(hours < 10) hours = '0' + hours let minutes = Math.floor(delta / 60) % 60 delta -= minutes * 60 - if(minutes < 10) minutes = '0' + minutes let seconds = Math.floor(delta) % 60 - if(seconds < 10) seconds = '0' + seconds + delta -= seconds * 60 + + let milliseconds = delta * 1000 + + return { days, hours, minutes, seconds, milliseconds } + } + + function secondsToTimeLeft(date_now, date_future) { + const r = getDuration(date_future - date_now) + let days = r.days + let hours = r.hours + let minutes = r.minutes + let seconds = r.seconds + if(hours < 10) hours = '0' + hours + if(minutes < 10) minutes = '0' + minutes + if(seconds < 10) seconds = '0' + seconds return qsTr("%n day(s)", "", days) + ' ' + hours + ':' + minutes + ':' + seconds } - + + function durationTextShort(total) { + const r = getDuration(total) + let text = "" + if(r.days > 0) text += qsTr("%nd", "day", r.days) + " " + if(r.hours > 0) text += qsTr("%nh", "hours", r.hours) + " " + if(r.minutes > 0) text += qsTr("%nm", "minutes", r.minutes) + " " + if(r.seconds > 0) text += qsTr("%ns", "seconds", r.seconds) + " " + if(r.milliseconds > 0) text += qsTr("%nms", "milliseconds", r.milliseconds) + " " + if(text === "") text += qsTr("Instant") + + return text + } + function clone(obj) { return JSON.parse(JSON.stringify(obj)); } diff --git a/atomic_qt_design/qml/Exchange/SwapProgress.qml b/atomic_qt_design/qml/Exchange/SwapProgress.qml index 63f300fe2e..d48b62d9f3 100644 --- a/atomic_qt_design/qml/Exchange/SwapProgress.qml +++ b/atomic_qt_design/qml/Exchange/SwapProgress.qml @@ -62,7 +62,7 @@ ColumnLayout { // Title DefaultText { text_value: API.get().settings_pg.empty_string + (qsTr("Progress details") + " | " + - qsTr("%1 seconds", "SECONDS").arg(General.formatDouble(total_time_passed, 1))) + General.durationTextShort(General.formatDouble(total_time_passed, 1))) font.pixelSize: Style.textSize1 Layout.bottomMargin: 10 } @@ -159,7 +159,7 @@ ColumnLayout { visible: bar.visible font.pixelSize: Style.textSizeSmall2 - text_value: API.get().settings_pg.empty_string + (event ? qsTr("Took %1s", "SECONDS").arg(General.formatDouble(seconds_passed, 1)) : '') + text_value: API.get().settings_pg.empty_string + (event ? General.durationTextShort(seconds_passed) : '') color: Style.colorGreen } } From 05c3cd542734d0987e8bf3038e9697bad4545e9c Mon Sep 17 00:00:00 2001 From: naezith Date: Sat, 15 Aug 2020 15:52:13 +0300 Subject: [PATCH 320/515] feat(gui): milliseconds precision --- atomic_qt_design/qml/Constants/General.qml | 24 +++++++++---------- .../qml/Exchange/SwapProgress.qml | 10 ++++---- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/atomic_qt_design/qml/Constants/General.qml b/atomic_qt_design/qml/Constants/General.qml index 8ce0d611da..b2fd7aaad6 100644 --- a/atomic_qt_design/qml/Constants/General.qml +++ b/atomic_qt_design/qml/Constants/General.qml @@ -61,28 +61,28 @@ QtObject { return (new Date(timestamp * 1000)) } - function getDuration(total_seconds) { - let delta = Math.abs(total_seconds) + function getDuration(total_ms) { + let delta = Math.abs(total_ms) - let days = Math.floor(delta / 86400) - delta -= days * 86400 + let days = Math.floor(delta / 86400000) + delta -= days * 86400000 - let hours = Math.floor(delta / 3600) % 24 - delta -= hours * 3600 + let hours = Math.floor(delta / 3600000) % 24 + delta -= hours * 3600000 - let minutes = Math.floor(delta / 60) % 60 - delta -= minutes * 60 + let minutes = Math.floor(delta / 60000) % 60 + delta -= minutes * 60000 - let seconds = Math.floor(delta) % 60 - delta -= seconds * 60 + let seconds = Math.floor(delta / 1000) % 60 + delta -= seconds * 60000 - let milliseconds = delta * 1000 + let milliseconds = delta return { days, hours, minutes, seconds, milliseconds } } function secondsToTimeLeft(date_now, date_future) { - const r = getDuration(date_future - date_now) + const r = getDuration((date_future - date_now)*1000) let days = r.days let hours = r.hours let minutes = r.minutes diff --git a/atomic_qt_design/qml/Exchange/SwapProgress.qml b/atomic_qt_design/qml/Exchange/SwapProgress.qml index d48b62d9f3..ed3180400c 100644 --- a/atomic_qt_design/qml/Exchange/SwapProgress.qml +++ b/atomic_qt_design/qml/Exchange/SwapProgress.qml @@ -44,7 +44,7 @@ ColumnLayout { } } - return sum / 1000 + return sum } readonly property int current_event_idx: { @@ -81,7 +81,7 @@ ColumnLayout { return details.events[idx] } - readonly property double seconds_passed: { + readonly property double time_passed: { if(!event) return 0 if(!event.started_at) return 0 if(!event.timestamp) return 0 @@ -89,7 +89,7 @@ ColumnLayout { let start = event.started_at if(index === 0) start *= 1000 - return (event.timestamp - start)/1000 + return event.timestamp - start } readonly property bool is_current_event: index === current_event_idx @@ -149,7 +149,7 @@ ColumnLayout { color: Style.colorWhite8 Rectangle { - width: parent.width * (total_time_passed > 0 ? (seconds_passed / total_time_passed) : 0) + width: parent.width * (total_time_passed > 0 ? (time_passed / total_time_passed) : 0) height: parent.height color: Style.colorGreen } @@ -159,7 +159,7 @@ ColumnLayout { visible: bar.visible font.pixelSize: Style.textSizeSmall2 - text_value: API.get().settings_pg.empty_string + (event ? General.durationTextShort(seconds_passed) : '') + text_value: API.get().settings_pg.empty_string + (event ? General.durationTextShort(time_passed) : '') color: Style.colorGreen } } From d7aecaec482d4313a631083d0950bfdabc6cf5ef Mon Sep 17 00:00:00 2001 From: naezith Date: Sat, 15 Aug 2020 17:20:41 +0300 Subject: [PATCH 321/515] feat(gui): add started_at for the error events --- atomic_qt_design/qml/Constants/General.qml | 8 +-- .../qml/Exchange/SwapProgress.qml | 52 +++++++++++-------- 2 files changed, 35 insertions(+), 25 deletions(-) diff --git a/atomic_qt_design/qml/Constants/General.qml b/atomic_qt_design/qml/Constants/General.qml index b2fd7aaad6..31df1bfe59 100644 --- a/atomic_qt_design/qml/Constants/General.qml +++ b/atomic_qt_design/qml/Constants/General.qml @@ -74,7 +74,7 @@ QtObject { delta -= minutes * 60000 let seconds = Math.floor(delta / 1000) % 60 - delta -= seconds * 60000 + delta -= seconds * 1000 let milliseconds = delta @@ -96,12 +96,14 @@ QtObject { function durationTextShort(total) { const r = getDuration(total) + + r.seconds += r.milliseconds/1000 + let text = "" if(r.days > 0) text += qsTr("%nd", "day", r.days) + " " if(r.hours > 0) text += qsTr("%nh", "hours", r.hours) + " " if(r.minutes > 0) text += qsTr("%nm", "minutes", r.minutes) + " " - if(r.seconds > 0) text += qsTr("%ns", "seconds", r.seconds) + " " - if(r.milliseconds > 0) text += qsTr("%nms", "milliseconds", r.milliseconds) + " " + if(r.seconds > 0) text += qsTr("%1s", "seconds").arg(General.formatDouble(r.seconds, 3)) + " " if(text === "") text += qsTr("Instant") return text diff --git a/atomic_qt_design/qml/Exchange/SwapProgress.qml b/atomic_qt_design/qml/Exchange/SwapProgress.qml index ed3180400c..ad200b1da3 100644 --- a/atomic_qt_design/qml/Exchange/SwapProgress.qml +++ b/atomic_qt_design/qml/Exchange/SwapProgress.qml @@ -12,7 +12,7 @@ ColumnLayout { readonly property bool has_error_event: { if(!details) return false - const events = details.events + const events = corrected_events for(let i = events.length - 1; i >= 0; --i) if(details.error_events.indexOf(events[i].state) !== -1) @@ -21,27 +21,39 @@ ColumnLayout { return false } - readonly property var all_events: !details ? [] : has_error_event ? details.events.map(e => e.state) : details.success_events + readonly property var all_events: !details ? [] : has_error_event ? corrected_events.map(e => e.state) : details.success_events property var details + property var corrected_events + + onDetailsChanged: { + if(!details) return + + let events = General.clone(details.events) + + // Start timestamp of Started is in seconds somehow + if(events.length > 0) events[0].started_at *= 1000 + + // Set the missing started_at timestamps + if(events.length >= 2) { + for(let i = 1; i < events.length; ++i) { + if(!events[i].started_at) + events[i].started_at = events[i - 1].timestamp + } + } + + corrected_events = events + } + readonly property double total_time_passed: { if(!details) return 0 - const events = details.events + const events = corrected_events if(events.length === 0) return 0 let sum = 0 for(let i = 0; i < events.length; ++i) { const e = events[i] - let start = e.started_at - let end = e.timestamp - - // Start timestamp of Started is seconds somehow - if(e.state === "Started") - start *= 1000 - - if(start !== undefined && end !== undefined) { - sum += end - start - } + sum += e.timestamp - e.started_at } return sum @@ -49,7 +61,7 @@ ColumnLayout { readonly property int current_event_idx: { if(!details) return -1 - const events = details.events + const events = corrected_events if(events.length === 0) return -1 if(all_events.length === 0) return -1 @@ -61,8 +73,7 @@ ColumnLayout { // Title DefaultText { - text_value: API.get().settings_pg.empty_string + (qsTr("Progress details") + " | " + - General.durationTextShort(General.formatDouble(total_time_passed, 1))) + text_value: API.get().settings_pg.empty_string + (qsTr("Progress details") + " | " + General.durationTextShort(total_time_passed)) font.pixelSize: Style.textSize1 Layout.bottomMargin: 10 } @@ -75,10 +86,10 @@ ColumnLayout { delegate: Item { readonly property var event: { if(!details) return undefined - const idx = details.events.map(e => e.state).indexOf(modelData) + const idx = corrected_events.map(e => e.state).indexOf(modelData) if(idx === -1) return undefined - return details.events[idx] + return corrected_events[idx] } readonly property double time_passed: { @@ -86,10 +97,7 @@ ColumnLayout { if(!event.started_at) return 0 if(!event.timestamp) return 0 - let start = event.started_at - if(index === 0) start *= 1000 - - return event.timestamp - start + return event.timestamp - event.started_at } readonly property bool is_current_event: index === current_event_idx From 0886f4a91bd27dc60224855c5c76159684b56eeb Mon Sep 17 00:00:00 2001 From: naezith Date: Sat, 15 Aug 2020 18:16:47 +0300 Subject: [PATCH 322/515] feat(gui): add translatable texts for swap events --- atomic_qt_design/qml/Exchange/Exchange.qml | 51 +++++++++++++++++++ .../qml/Exchange/SwapProgress.qml | 2 +- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/atomic_qt_design/qml/Exchange/Exchange.qml b/atomic_qt_design/qml/Exchange/Exchange.qml index 79c2af7fc3..a497c2b75e 100644 --- a/atomic_qt_design/qml/Exchange/Exchange.qml +++ b/atomic_qt_design/qml/Exchange/Exchange.qml @@ -204,6 +204,57 @@ Item { function getStatusTextWithPrefix(status) { return getStatusStep(status) + " " + getStatusText(status) } + + function getEventText(event_name) { + switch(event_name) { + case "Started": + return qsTr("Started") + case "Negotiated": + return qsTr("Negotiated") + case "TakerFeeSent": + return qsTr("Taker fee sent") + case "MakerPaymentReceived": + return qsTr("Maker payment received") + case "MakerPaymentWaitConfirmStarted": + return qsTr("Maker payment wait confirm started") + case "MakerPaymentValidatedAndConfirmed": + return qsTr("Maker payment validated and confirmed") + case "TakerPaymentSent": + return qsTr("Taker payment sent") + case "TakerPaymentSpent": + return qsTr("Taker payment spent") + case "MakerPaymentSpent": + return qsTr("Maker payment spent") + case "Finished": + return qsTr("Finished") + case "StartFailed": + return qsTr("Start failed") + case "NegotiateFailed": + return qsTr("Negotiate failed") + case "TakerFeeValidateFailed": + return qsTr("Taker fee validate failed") + case "MakerPaymentTransactionFailed": + return qsTr("Maker payment transaction failed") + case "MakerPaymentDataSendFailed": + return qsTr("Maker payment Data send failed") + case "MakerPaymentWaitConfirmFailed": + return qsTr("Maker payment wait confirm failed") + case "TakerPaymentValidateFailed": + return qsTr("Taker payment validate failed") + case "TakerPaymentWaitConfirmFailed": + return qsTr("Taker payment wait confirm failed") + case "TakerPaymentSpendFailed": + return qsTr("Taker payment spend failed") + case "MakerPaymentWaitRefundStarted": + return qsTr("Maker payment wait refund started") + case "MakerPaymentRefunded": + return qsTr("Maker payment refunded") + case "MakerPaymentRefundFailed": + return qsTr("Maker payment refund failed") + default: + return qsTr(event_name) + } + } } diff --git a/atomic_qt_design/qml/Exchange/SwapProgress.qml b/atomic_qt_design/qml/Exchange/SwapProgress.qml index ad200b1da3..0bf2a56466 100644 --- a/atomic_qt_design/qml/Exchange/SwapProgress.qml +++ b/atomic_qt_design/qml/Exchange/SwapProgress.qml @@ -144,7 +144,7 @@ ColumnLayout { font.pixelSize: Style.textSizeSmall4 - text_value: API.get().settings_pg.empty_string + (modelData) + text_value: API.get().settings_pg.empty_string + (getEventText(modelData)) color: event ? Style.colorText : is_current_event ? Style.colorText2 : Style.colorTextDisabled } From 5671e5b7ab4e563476e16bf4f051eae5a92ff33a Mon Sep 17 00:00:00 2001 From: romanszterg Date: Sat, 15 Aug 2020 18:19:29 +0200 Subject: [PATCH 323/515] feat(swap): add update of kind of events --- src/atomic.dex.qt.orders.model.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/atomic.dex.qt.orders.model.cpp b/src/atomic.dex.qt.orders.model.cpp index ca6d0944a8..864dfd4140 100644 --- a/src/atomic.dex.qt.orders.model.cpp +++ b/src/atomic.dex.qt.orders.model.cpp @@ -376,6 +376,8 @@ namespace atomic_dex update_value(OrdersRoles::OrderErrorStateRole, state, idx, *this); update_value(OrdersRoles::OrderErrorMessageRole, msg, idx, *this); update_value(OrdersRoles::EventsRole, nlohmann_json_array_to_qt_json_array(contents.events), idx, *this); + update_value(OrdersRoles::SuccessEventsRole, vector_std_string_to_qt_string_list(contents.success_events), idx, *this); + update_value(OrdersRoles::ErrorEventsRole, vector_std_string_to_qt_string_list(contents.error_events), idx, *this); emit lengthChanged(); } else From 4e9cf731e2a50307b3c3b89da4e9f60350eba1fe Mon Sep 17 00:00:00 2001 From: romanszterg Date: Sat, 15 Aug 2020 18:22:11 +0200 Subject: [PATCH 324/515] feat(swap): update event --- src/atomic.dex.qt.orders.model.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/atomic.dex.qt.orders.model.cpp b/src/atomic.dex.qt.orders.model.cpp index 864dfd4140..25f4b0b816 100644 --- a/src/atomic.dex.qt.orders.model.cpp +++ b/src/atomic.dex.qt.orders.model.cpp @@ -376,6 +376,7 @@ namespace atomic_dex update_value(OrdersRoles::OrderErrorStateRole, state, idx, *this); update_value(OrdersRoles::OrderErrorMessageRole, msg, idx, *this); update_value(OrdersRoles::EventsRole, nlohmann_json_array_to_qt_json_array(contents.events), idx, *this); + update_value(OrdersRoles::SuccessEventsRole, vector_std_string_to_qt_string_list(contents.success_events), idx, *this); update_value(OrdersRoles::ErrorEventsRole, vector_std_string_to_qt_string_list(contents.error_events), idx, *this); emit lengthChanged(); From 7a2a6c6e9d3ebeb22c656d3e441edba54dea8123 Mon Sep 17 00:00:00 2001 From: naezith Date: Sat, 15 Aug 2020 19:56:45 +0300 Subject: [PATCH 325/515] feat(gui): fix swap progress not live updating --- .../qml/Exchange/SwapProgress.qml | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/SwapProgress.qml b/atomic_qt_design/qml/Exchange/SwapProgress.qml index 0bf2a56466..a439259e9a 100644 --- a/atomic_qt_design/qml/Exchange/SwapProgress.qml +++ b/atomic_qt_design/qml/Exchange/SwapProgress.qml @@ -9,26 +9,19 @@ import "../Constants" ColumnLayout { id: root - readonly property bool has_error_event: { - if(!details) return false - - const events = corrected_events - - for(let i = events.length - 1; i >= 0; --i) - if(details.error_events.indexOf(events[i].state) !== -1) - return true + property var details + // QML Hack to get the events for .events field, because onDetailsChanged is not being triggered + property var details_events: !details ? [] : details.events - return false - } + // MM2 data needs some modifications, see onDetails_eventsChanged + property var corrected_events: ([]) readonly property var all_events: !details ? [] : has_error_event ? corrected_events.map(e => e.state) : details.success_events - property var details - property var corrected_events - onDetailsChanged: { - if(!details) return + onDetails_eventsChanged: { + if(!details_events) return - let events = General.clone(details.events) + let events = General.clone(details_events) // Start timestamp of Started is in seconds somehow if(events.length > 0) events[0].started_at *= 1000 @@ -44,6 +37,18 @@ ColumnLayout { corrected_events = events } + readonly property bool has_error_event: { + if(!details) return false + + const events = corrected_events + + for(let i = events.length - 1; i >= 0; --i) + if(details.error_events.indexOf(events[i].state) !== -1) + return true + + return false + } + readonly property double total_time_passed: { if(!details) return 0 From dd4bf2907d3d7944f8b3e3761b0bbe2d4714382a Mon Sep 17 00:00:00 2001 From: romanszterg Date: Sat, 15 Aug 2020 19:24:37 +0200 Subject: [PATCH 326/515] feat(swap): refresh every 5 second now --- src/atomic.dex.mm2.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/atomic.dex.mm2.cpp b/src/atomic.dex.mm2.cpp index a6e41a0e9c..825a073fa2 100644 --- a/src/atomic.dex.mm2.cpp +++ b/src/atomic.dex.mm2.cpp @@ -158,6 +158,12 @@ namespace atomic_dex if (s >= 5s) { spawn([this]() { fetch_current_orderbook_thread(false); }); + spawn([this]() { + std::vector> futures; + futures.emplace_back(spawn([this]() { process_orders(); })); + futures.emplace_back(spawn([this]() { process_swaps(); })); + for (auto&& fut: futures) { fut.get(); } + }); m_orderbook_clock = std::chrono::high_resolution_clock::now(); } @@ -541,11 +547,7 @@ namespace atomic_dex t_coins coins = get_enabled_coins(); std::vector> futures; - futures.reserve(coins.size() * 2 + 2); - - futures.emplace_back(spawn([this]() { process_orders(); })); - - futures.emplace_back(spawn([this]() { process_swaps(); })); + futures.reserve(coins.size() * 2); for (auto&& current_coin: coins) { From eb25e8c60d6108bfef469907c2e42d13ea76362c Mon Sep 17 00:00:00 2001 From: romanszterg Date: Sat, 15 Aug 2020 19:40:24 +0200 Subject: [PATCH 327/515] feat(app): refresh every 50 ms now --- src/atomic.dex.app.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index 353b673912..3b976d501d 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -52,7 +52,7 @@ namespace { - constexpr std::size_t g_timeout_q_timer_ms = 8; + constexpr std::size_t g_timeout_q_timer_ms = 50; #if defined(_WIN32) || defined(WIN32) bool From 19b69431384430f99423149d7c5560342f24c226 Mon Sep 17 00:00:00 2001 From: naezith Date: Sat, 15 Aug 2020 20:46:59 +0300 Subject: [PATCH 328/515] feat(gui): fix is_maker of undefined --- atomic_qt_design/qml/Exchange/OrderModal.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomic_qt_design/qml/Exchange/OrderModal.qml b/atomic_qt_design/qml/Exchange/OrderModal.qml index 57dd264371..125e73cd9b 100644 --- a/atomic_qt_design/qml/Exchange/OrderModal.qml +++ b/atomic_qt_design/qml/Exchange/OrderModal.qml @@ -170,7 +170,7 @@ DefaultModal { } SwapProgress { - visible: details !== undefined && !details.is_maker + visible: details && !details.is_maker Layout.fillWidth: true details: root.details } From 3e17da0da763cb6cb7dd89402eb451101879f53d Mon Sep 17 00:00:00 2001 From: romanszterg Date: Sat, 15 Aug 2020 20:11:16 +0200 Subject: [PATCH 329/515] feat(app): refresh every 100 ms now --- src/atomic.dex.app.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index 3b976d501d..6e6bc08963 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -52,7 +52,7 @@ namespace { - constexpr std::size_t g_timeout_q_timer_ms = 50; + constexpr std::size_t g_timeout_q_timer_ms = 100; #if defined(_WIN32) || defined(WIN32) bool @@ -228,8 +228,9 @@ namespace atomic_dex } system_manager_.get_system().process_action(); - if (not this->m_actions_queue.empty() && not m_event_actions[events_action::about_to_exit_app]) + while (not this->m_actions_queue.empty()) { + if (m_event_actions[events_action::about_to_exit_app]) break; action last_action; this->m_actions_queue.pop(last_action); switch (last_action) From 516ec8dc7ca41fe977907ca3389d59b1725a3ba8 Mon Sep 17 00:00:00 2001 From: naezith Date: Sat, 15 Aug 2020 21:40:17 +0300 Subject: [PATCH 330/515] feat(gui): add exists(), code polish --- atomic_qt_design/qml/Components/Toast.qml | 2 +- atomic_qt_design/qml/Constants/General.qml | 11 ++++++++--- atomic_qt_design/qml/Exchange/OrderModal.qml | 2 +- atomic_qt_design/qml/Exchange/Trade/OrderForm.qml | 2 +- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 4 ++-- 5 files changed, 13 insertions(+), 8 deletions(-) diff --git a/atomic_qt_design/qml/Components/Toast.qml b/atomic_qt_design/qml/Components/Toast.qml index 50818862c5..928ce2ac67 100644 --- a/atomic_qt_design/qml/Components/Toast.qml +++ b/atomic_qt_design/qml/Components/Toast.qml @@ -50,7 +50,7 @@ Rectangle { margins: margin / 2 } font.pixelSize: Style.textSizeSmall2 - text_value: title + (details !== undefined && details !== "" ? (" - " + qsTr("Click here to see the details")) : "") + text_value: title + (General.fieldExists(details) ? (" - " + qsTr("Click here to see the details")) : "") } SequentialAnimation on opacity { diff --git a/atomic_qt_design/qml/Constants/General.qml b/atomic_qt_design/qml/Constants/General.qml index 31df1bfe59..6dab605254 100644 --- a/atomic_qt_design/qml/Constants/General.qml +++ b/atomic_qt_design/qml/Constants/General.qml @@ -235,11 +235,16 @@ QtObject { } function isZero(v) { - return !fieldExists(v) || parseFloat(v) === 0 + return !isFilled(v) || parseFloat(v) === 0 } - function fieldExists(v) { - return v !== undefined && v !== "" + + function exists(v) { + return v !== undefined && v !== null + } + + function isFilled(v) { + return exists(v) && v !== "" } function isEthNeeded() { diff --git a/atomic_qt_design/qml/Exchange/OrderModal.qml b/atomic_qt_design/qml/Exchange/OrderModal.qml index 125e73cd9b..7d4ea05759 100644 --- a/atomic_qt_design/qml/Exchange/OrderModal.qml +++ b/atomic_qt_design/qml/Exchange/OrderModal.qml @@ -170,7 +170,7 @@ DefaultModal { } SwapProgress { - visible: details && !details.is_maker + visible: General.exists(details) && !details.is_maker Layout.fillWidth: true details: root.details } diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index 39a1903c57..4077481c1c 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -29,7 +29,7 @@ FloatingBackground { } function hasEthFees() { - return General.fieldExists(curr_trade_info.erc_fees) && parseFloat(curr_trade_info.erc_fees) > 0 + return General.isFilled(curr_trade_info.erc_fees) && parseFloat(curr_trade_info.erc_fees) > 0 } function hasEnoughEthForFees() { diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index 7a07273cbb..06c33cb60b 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -243,11 +243,11 @@ Item { } } else { - if(default_config.requires_notarization !== undefined && default_config.requires_notarization !== null) { + if(General.exists(default_config.requires_notarization)) { nota = default_config.requires_notarization ? "1" : "0" } - if(nota !== "1" && default_config.required_confirmations !== undefined && default_config.required_confirmations !== null) { + if(nota !== "1" && General.exists(default_config.required_confirmations)) { confs = default_config.required_confirmations.toString() } } From 5c2d9cb6a3137193507d0074f7f87f4317667907 Mon Sep 17 00:00:00 2001 From: naezith Date: Sat, 15 Aug 2020 21:41:53 +0300 Subject: [PATCH 331/515] feat(gui): add exists(), code polish --- atomic_qt_design/qml/Components/Toast.qml | 2 +- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/Components/Toast.qml b/atomic_qt_design/qml/Components/Toast.qml index 928ce2ac67..9073ba0be8 100644 --- a/atomic_qt_design/qml/Components/Toast.qml +++ b/atomic_qt_design/qml/Components/Toast.qml @@ -50,7 +50,7 @@ Rectangle { margins: margin / 2 } font.pixelSize: Style.textSizeSmall2 - text_value: title + (General.fieldExists(details) ? (" - " + qsTr("Click here to see the details")) : "") + text_value: title + (General.isFilled(details) ? (" - " + qsTr("Click here to see the details")) : "") } SequentialAnimation on opacity { diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index 06c33cb60b..f502f06ea6 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -160,7 +160,7 @@ Item { const rel = rel_ticker const amount = sell_mode ? getCurrentForm().getVolume() : General.formatDouble(getCurrentForm().getNeededAmountToSpend(getCurrentForm().getVolume())) - if(force || (General.fieldExists(base) && General.fieldExists(rel) && !General.isZero(amount))) { + if(force || (General.isFilled(base) && General.isFilled(rel) && !General.isZero(amount))) { getTradeInfo(base, rel, amount) // Since new implementation does not update fees instantly, re-cap the volume every time, just in case From e9a7e6c73059fcbaffcdda7d9c87c44e3dad9b2c Mon Sep 17 00:00:00 2001 From: naezith Date: Sat, 15 Aug 2020 21:51:36 +0300 Subject: [PATCH 332/515] feat(gui): cleanup at modal close --- atomic_qt_design/qml/Exchange/OrderModal.qml | 2 ++ atomic_qt_design/qml/Exchange/SwapProgress.qml | 4 +--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/OrderModal.qml b/atomic_qt_design/qml/Exchange/OrderModal.qml index 7d4ea05759..98cc23f006 100644 --- a/atomic_qt_design/qml/Exchange/OrderModal.qml +++ b/atomic_qt_design/qml/Exchange/OrderModal.qml @@ -17,6 +17,8 @@ DefaultModal { if(!details) root.close() } + onClosed: details = undefined + // Inside modal ColumnLayout { width: parent.width diff --git a/atomic_qt_design/qml/Exchange/SwapProgress.qml b/atomic_qt_design/qml/Exchange/SwapProgress.qml index a439259e9a..724a6bdf7a 100644 --- a/atomic_qt_design/qml/Exchange/SwapProgress.qml +++ b/atomic_qt_design/qml/Exchange/SwapProgress.qml @@ -98,9 +98,7 @@ ColumnLayout { } readonly property double time_passed: { - if(!event) return 0 - if(!event.started_at) return 0 - if(!event.timestamp) return 0 + if(!event || !event.started_at || !event.timestamp) return 0 return event.timestamp - event.started_at } From 323171dd550fa7b90139c9965ac96bc442a9821d Mon Sep 17 00:00:00 2001 From: romanszterg Date: Sat, 15 Aug 2020 21:17:27 +0200 Subject: [PATCH 333/515] feat(details_swap_progress): add average time --- src/atomic.dex.qt.orders.model.cpp | 31 ++++++++++++++++++++++++++++++ src/atomic.dex.qt.orders.model.hpp | 26 +++++++++++++++++++------ 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/src/atomic.dex.qt.orders.model.cpp b/src/atomic.dex.qt.orders.model.cpp index 25f4b0b816..be72e0ec9e 100644 --- a/src/atomic.dex.qt.orders.model.cpp +++ b/src/atomic.dex.qt.orders.model.cpp @@ -561,4 +561,35 @@ namespace atomic_dex this->m_model_data.clear(); this->endResetModel(); } +} // namespace atomic_dex + +namespace atomic_dex +{ + QVariant + atomic_dex::orders_model::get_average_events_time_registry() const noexcept + { + return m_json_time_registry; + } + + void + atomic_dex::orders_model::set_average_events_time_registry(const QString& event_name, double time) noexcept + { + m_json_time_registry[event_name] = time; + emit onAverageEventsTimeRegistryChanged(); + } +} + +//! QML Api +namespace atomic_dex +{ + void + orders_model::save_event_time(const QString& uuid, const QString& event_name, double time) + { + m_events_time_registry[uuid][event_name] = time; + double average = std::accumulate( + begin(m_events_time_registry), end(m_events_time_registry), 0.0, + [event_name](double accumulator, auto&& cur) { return accumulator + cur.second[event_name]; }) / + m_events_time_registry[uuid].size(); + set_average_events_time_registry(event_name, average); + } } // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.orders.model.hpp b/src/atomic.dex.qt.orders.model.hpp index 584b39a4db..3eaac06ce5 100644 --- a/src/atomic.dex.qt.orders.model.hpp +++ b/src/atomic.dex.qt.orders.model.hpp @@ -18,6 +18,8 @@ //! QT #include +#include +#include #include //! PCH @@ -35,6 +37,7 @@ namespace atomic_dex Q_OBJECT Q_PROPERTY(orders_proxy_model* orders_proxy_mdl READ get_orders_proxy_mdl NOTIFY ordersProxyChanged); Q_PROPERTY(int length READ get_length NOTIFY lengthChanged); + Q_PROPERTY(QVariant average_events_time_registry READ get_average_events_time_registry NOTIFY onAverageEventsTimeRegistryChanged) Q_ENUMS(OrdersRoles) public: enum OrdersRoles @@ -79,22 +82,33 @@ namespace atomic_dex //! Properties [[nodiscard]] int get_length() const noexcept; [[nodiscard]] orders_proxy_model* get_orders_proxy_mdl() const noexcept; + [[nodiscard]] QVariant get_average_events_time_registry() const noexcept; + + + //! QML API + Q_INVOKABLE void save_event_time(const QString& uuid, const QString& event_name, double time); signals: void lengthChanged(); void ordersProxyChanged(); + void onAverageEventsTimeRegistryChanged(); private: + void set_average_events_time_registry(const QString& event_name, double time) noexcept; + ag::ecs::system_manager& m_system_manager; entt::dispatcher& m_dispatcher; - using t_orders_datas = QVector; - using t_orders_id_registry = std::unordered_set; - using t_swaps_id_registry = std::unordered_set; + using t_orders_datas = QVector; + using t_orders_id_registry = std::unordered_set; + using t_swaps_id_registry = std::unordered_set; + using t_time_events_registry = std::unordered_map>; - t_orders_id_registry m_orders_id_registry; - t_swaps_id_registry m_swaps_id_registry; - t_orders_datas m_model_data; + t_orders_id_registry m_orders_id_registry; + t_swaps_id_registry m_swaps_id_registry; + t_orders_datas m_model_data; + t_time_events_registry m_events_time_registry; + QJsonObject m_json_time_registry; orders_proxy_model* m_model_proxy; From 56750137fed500b570f6c95ecf6e7dd76a0e0437 Mon Sep 17 00:00:00 2001 From: naezith Date: Sat, 15 Aug 2020 22:31:23 +0300 Subject: [PATCH 334/515] feat(gui): add live timer --- .../qml/Exchange/SwapProgress.qml | 33 +++++++++++++++---- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/SwapProgress.qml b/atomic_qt_design/qml/Exchange/SwapProgress.qml index 724a6bdf7a..9819f5d077 100644 --- a/atomic_qt_design/qml/Exchange/SwapProgress.qml +++ b/atomic_qt_design/qml/Exchange/SwapProgress.qml @@ -70,15 +70,28 @@ ColumnLayout { if(events.length === 0) return -1 if(all_events.length === 0) return -1 - const idx = all_events.indexOf(events[events.length-1].state) + const last_state = events[events.length-1].state + if(last_state === "Finished") return -1 + + const idx = all_events.indexOf(last_state) if(idx === -1) return -1 return idx + 1 } + property double simulated_time: 0 + Timer { + running: current_event_idx !== -1 + interval: 1000 + repeat: true + onTriggered: simulated_time += interval + } + + onTotal_time_passedChanged: simulated_time = 0 + // Title DefaultText { - text_value: API.get().settings_pg.empty_string + (qsTr("Progress details") + " | " + General.durationTextShort(total_time_passed)) + text_value: API.get().settings_pg.empty_string + (qsTr("Progress details") + " | " + General.durationTextShort(total_time_passed + simulated_time)) font.pixelSize: Style.textSize1 Layout.bottomMargin: 10 } @@ -98,20 +111,26 @@ ColumnLayout { } readonly property double time_passed: { + if(is_current_event) return simulated_time + if(!event || !event.started_at || !event.timestamp) return 0 - return event.timestamp - event.started_at + const diff = event.timestamp - event.started_at + + return diff } readonly property bool is_current_event: index === current_event_idx + readonly property bool is_active: General.exists(event) || is_current_event + width: root.width height: 50 DefaultText { id: icon - text_value: event || is_current_event ? "●" : "○" + text_value: is_active ? "●" : "○" anchors.left: parent.left anchors.leftMargin: 10 anchors.verticalCenter: col_layout.verticalCenter @@ -153,14 +172,14 @@ ColumnLayout { Rectangle { id: bar - visible: event ? true : false + visible: is_active width: 300 height: 2 color: Style.colorWhite8 Rectangle { - width: parent.width * (total_time_passed > 0 ? (time_passed / total_time_passed) : 0) + width: parent.width * (total_time_passed > 0 ? (time_passed / (total_time_passed + simulated_time)) : 0) height: parent.height color: Style.colorGreen } @@ -170,7 +189,7 @@ ColumnLayout { visible: bar.visible font.pixelSize: Style.textSizeSmall2 - text_value: API.get().settings_pg.empty_string + (event ? General.durationTextShort(time_passed) : '') + text_value: API.get().settings_pg.empty_string + (is_active ? General.durationTextShort(time_passed) : '') color: Style.colorGreen } } From bb0c64eaf42f972f0f086cff856622def3f5b6c3 Mon Sep 17 00:00:00 2001 From: naezith Date: Sat, 15 Aug 2020 22:36:21 +0300 Subject: [PATCH 335/515] feat(gui): remove started_at*1000 fix for Started --- atomic_qt_design/qml/Exchange/SwapProgress.qml | 3 --- 1 file changed, 3 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/SwapProgress.qml b/atomic_qt_design/qml/Exchange/SwapProgress.qml index 9819f5d077..464bc616e4 100644 --- a/atomic_qt_design/qml/Exchange/SwapProgress.qml +++ b/atomic_qt_design/qml/Exchange/SwapProgress.qml @@ -23,9 +23,6 @@ ColumnLayout { let events = General.clone(details_events) - // Start timestamp of Started is in seconds somehow - if(events.length > 0) events[0].started_at *= 1000 - // Set the missing started_at timestamps if(events.length >= 2) { for(let i = 1; i < events.length; ++i) { From 36d169640219a246567d75761bf00587dbec307f Mon Sep 17 00:00:00 2001 From: romanszterg Date: Sat, 15 Aug 2020 21:44:15 +0200 Subject: [PATCH 336/515] feat(details_swap_progress): started_at for Started event --- src/atomic.dex.mm2.api.cpp | 137 +++++++---------------------- src/atomic.dex.qt.orders.model.cpp | 32 +++---- 2 files changed, 48 insertions(+), 121 deletions(-) diff --git a/src/atomic.dex.mm2.api.cpp b/src/atomic.dex.mm2.api.cpp index 64aedea98d..34ff686fe6 100644 --- a/src/atomic.dex.mm2.api.cpp +++ b/src/atomic.dex.mm2.api.cpp @@ -721,6 +721,8 @@ namespace mm2::api using namespace date; using namespace std::chrono; + nlohmann::json j_cpy = j; + j.at("error_events").get_to(contents.error_events); j.at("success_events").get_to(contents.success_events); j.at("uuid").get_to(contents.uuid); @@ -743,127 +745,52 @@ namespace mm2::api contents.my_info["my_amount"] = adjust_precision(contents.my_info["my_amount"].get()); } } - using t_event_timestamp_registry = std::unordered_map; - t_event_timestamp_registry event_timestamp_registry; - double total_time_in_seconds = 0.00; + // using t_event_timestamp_registry = std::unordered_map; + // t_event_timestamp_registry event_timestamp_registry; + // double total_time_in_seconds = 0.00; - for (auto&& content: j.at("events")) + for (nlohmann::json& content: j_cpy.at("events")) { - const nlohmann::json& j_evt = content.at("event"); - auto timestamp = content.at("timestamp").get(); - std::string human_date = to_human_date(timestamp, "%F %T"); - auto evt_type = j_evt.at("type").get(); - - auto rate_bundler = [&event_timestamp_registry, - &total_time_in_seconds](nlohmann::json& jf_evt, const std::string& event_type, const std::string& previous_event) { - if (event_timestamp_registry.count(previous_event) != 0) - { - std::int64_t ts = event_timestamp_registry.at(previous_event); - jf_evt["started_at"] = ts; - std::int64_t ts2 = jf_evt.at("timestamp").get(); - std::stringstream ss; - sys_time t1{std::chrono::milliseconds{ts}}; - sys_time t2{std::chrono::milliseconds{ts2}}; - double res; - res = (std::chrono::duration_cast(t2 - t1).count() / 1000.0); - ss << std::fixed << std::setprecision(3) << res; - jf_evt["time_difference_gui"] = ss.str() + "s"; - event_timestamp_registry[event_type] = ts2; // Negotiated finished at this time - total_time_in_seconds += res; - } - }; + nlohmann::json& j_evt = content.at("event"); + auto timestamp = content.at("timestamp").get(); + std::string human_date = to_human_date(timestamp, "%F %T"); + auto evt_type = j_evt.at("type").get(); + + /* auto rate_bundler = [&event_timestamp_registry, + &total_time_in_seconds](nlohmann::json& jf_evt, const std::string& event_type, const std::string& previous_event) { + if (event_timestamp_registry.count(previous_event) != 0) + { + std::int64_t ts = event_timestamp_registry.at(previous_event); + jf_evt["started_at"] = ts; + std::int64_t ts2 = jf_evt.at("timestamp").get(); + std::stringstream ss; + sys_time t1{std::chrono::milliseconds{ts}}; + sys_time t2{std::chrono::milliseconds{ts2}}; + double res; + res = (std::chrono::duration_cast(t2 - t1).count() / 1000.0); + ss << std::fixed << std::setprecision(3) << res; + jf_evt["time_difference_gui"] = ss.str() + "s"; + event_timestamp_registry[event_type] = ts2; // Negotiated finished at this time + total_time_in_seconds += res; + } + };*/ + if (j_evt.count("data") == 0) { nlohmann::json jf_evt = {{"state", evt_type}, {"human_timestamp", human_date}, {"timestamp", timestamp}}; - - if (evt_type == "MakerPaymentWaitConfirmStarted") - { - rate_bundler(jf_evt, evt_type, "MakerPaymentReceived"); - } - - if (evt_type == "MakerPaymentValidatedAndConfirmed") - { - rate_bundler(jf_evt, evt_type, "MakerPaymentWaitConfirmStarted"); - } - - if (evt_type == "Finished") - { - if (contents.type == "Taker") - { - rate_bundler(jf_evt, evt_type, "MakerPaymentSpent"); - } - } - contents.events.push_back(jf_evt); } else { - nlohmann::json jf_evt = {{"state", evt_type}, {"human_timestamp", human_date}, {"data", j_evt.at("data")}, {"timestamp", timestamp}}; if (evt_type == "Started") { - jf_evt["started_at"] = jf_evt.at("data").at("started_at"); - std::int64_t ts = jf_evt.at("data").at("started_at").get() * 1000; - std::int64_t ts2 = jf_evt.at("timestamp").get(); - sys_time t1{std::chrono::milliseconds{ts}}; - sys_time t2{std::chrono::milliseconds{ts2}}; - std::stringstream ss; - double res; - res = (std::chrono::duration_cast(t2 - t1).count() / 1000.0); - ss << std::fixed << std::setprecision(3) << res; - jf_evt["time_difference_gui"] = ss.str() + "s"; - event_timestamp_registry["Started"] = ts2; // Started finished at this time - total_time_in_seconds += res; - } - - if (evt_type == "Negotiated") - { - rate_bundler(jf_evt, evt_type, "Started"); - } - - if (evt_type == "TakerFeeValidated" || evt_type == "TakerFeeSent") - { - rate_bundler(jf_evt, evt_type, "Negotiated"); - } - - if (evt_type == "MakerPaymentReceived") - { - rate_bundler(jf_evt, evt_type, "TakerFeeSent"); - } - - if (evt_type == "MakerPaymentSent") - { - rate_bundler(jf_evt, evt_type, "TakerFeeValidated"); - } - - if (evt_type == "TakerPaymentSent") - { - rate_bundler(jf_evt, evt_type, "MakerPaymentValidatedAndConfirmed"); - } - - if (evt_type == "TakerPaymentSpent") - { - if (contents.type == "Taker") - { - rate_bundler(jf_evt, evt_type, "TakerPaymentSent"); - } - else - { - rate_bundler(jf_evt, evt_type, "TakerPaymentValidatedAndConfirmed"); - } + j_evt["data"]["started_at"] = j_evt.at("data").at("started_at").get() * 1000; } - - if (evt_type == "MakerPaymentSpent") - { - rate_bundler(jf_evt, evt_type, "TakerPaymentSpent"); - } - + nlohmann::json jf_evt = {{"state", evt_type}, {"human_timestamp", human_date}, {"data", j_evt.at("data")}, {"timestamp", timestamp}}; contents.events.push_back(jf_evt); } } - std::stringstream ss; - ss << std::fixed << std::setprecision(3) << total_time_in_seconds; - contents.total_time_in_seconds = ss.str() + "s"; } void diff --git a/src/atomic.dex.qt.orders.model.cpp b/src/atomic.dex.qt.orders.model.cpp index be72e0ec9e..b9142f8363 100644 --- a/src/atomic.dex.qt.orders.model.cpp +++ b/src/atomic.dex.qt.orders.model.cpp @@ -563,6 +563,21 @@ namespace atomic_dex } } // namespace atomic_dex +//! QML Api +namespace atomic_dex +{ + void + orders_model::save_event_time(const QString& uuid, const QString& event_name, double time) + { + m_events_time_registry[uuid][event_name] = time; + double average = std::accumulate( + begin(m_events_time_registry), end(m_events_time_registry), 0.0, + [event_name](double accumulator, auto&& cur) { return accumulator + cur.second[event_name]; }) / + m_events_time_registry[uuid].size(); + set_average_events_time_registry(event_name, average); + } +} // namespace atomic_dex + namespace atomic_dex { QVariant @@ -577,19 +592,4 @@ namespace atomic_dex m_json_time_registry[event_name] = time; emit onAverageEventsTimeRegistryChanged(); } -} - -//! QML Api -namespace atomic_dex -{ - void - orders_model::save_event_time(const QString& uuid, const QString& event_name, double time) - { - m_events_time_registry[uuid][event_name] = time; - double average = std::accumulate( - begin(m_events_time_registry), end(m_events_time_registry), 0.0, - [event_name](double accumulator, auto&& cur) { return accumulator + cur.second[event_name]; }) / - m_events_time_registry[uuid].size(); - set_average_events_time_registry(event_name, average); - } -} // namespace atomic_dex \ No newline at end of file +} \ No newline at end of file From 9bb9cdbf0d41b02f3c52e8715917cd7f3566e564 Mon Sep 17 00:00:00 2001 From: naezith Date: Sat, 15 Aug 2020 23:07:48 +0300 Subject: [PATCH 337/515] feat(gui): add started_at for missing ones --- atomic_qt_design/qml/Exchange/SwapProgress.qml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/SwapProgress.qml b/atomic_qt_design/qml/Exchange/SwapProgress.qml index 464bc616e4..77321d51af 100644 --- a/atomic_qt_design/qml/Exchange/SwapProgress.qml +++ b/atomic_qt_design/qml/Exchange/SwapProgress.qml @@ -24,9 +24,11 @@ ColumnLayout { let events = General.clone(details_events) // Set the missing started_at timestamps - if(events.length >= 2) { - for(let i = 1; i < events.length; ++i) { - if(!events[i].started_at) + for(let i = 0; i < events.length; ++i) { + if(!events[i].started_at) { + if(events[i].data && events[i].data.started_at) + events[i].started_at = events[i].data.started_at + else if(i > 0) events[i].started_at = events[i - 1].timestamp } } @@ -55,6 +57,7 @@ ColumnLayout { let sum = 0 for(let i = 0; i < events.length; ++i) { const e = events[i] + console.log(i,"index:", e.started_at, e.timestamp, " = ", e.timestamp - e.started_at) sum += e.timestamp - e.started_at } From c52cb539a9066cd3a567ed236152af9f37cfd76f Mon Sep 17 00:00:00 2001 From: romanszterg Date: Sat, 15 Aug 2020 22:34:50 +0200 Subject: [PATCH 338/515] feat(details_swap_progress): add time diff --- src/atomic.dex.mm2.api.cpp | 82 +++++++++++++++++++++++--------------- src/atomic.dex.mm2.api.hpp | 4 +- 2 files changed, 52 insertions(+), 34 deletions(-) diff --git a/src/atomic.dex.mm2.api.cpp b/src/atomic.dex.mm2.api.cpp index 34ff686fe6..54b9be0e81 100644 --- a/src/atomic.dex.mm2.api.cpp +++ b/src/atomic.dex.mm2.api.cpp @@ -721,8 +721,6 @@ namespace mm2::api using namespace date; using namespace std::chrono; - nlohmann::json j_cpy = j; - j.at("error_events").get_to(contents.error_events); j.at("success_events").get_to(contents.success_events); j.at("uuid").get_to(contents.uuid); @@ -745,52 +743,72 @@ namespace mm2::api contents.my_info["my_amount"] = adjust_precision(contents.my_info["my_amount"].get()); } } - // using t_event_timestamp_registry = std::unordered_map; - // t_event_timestamp_registry event_timestamp_registry; - // double total_time_in_seconds = 0.00; + using t_event_timestamp_registry = std::unordered_map; + t_event_timestamp_registry event_timestamp_registry; + double total_time_in_ms = 0.00; - for (nlohmann::json& content: j_cpy.at("events")) + std::size_t idx = 0; + const auto& events = j.at("events"); + for (auto&& content: events) { - nlohmann::json& j_evt = content.at("event"); - auto timestamp = content.at("timestamp").get(); - std::string human_date = to_human_date(timestamp, "%F %T"); - auto evt_type = j_evt.at("type").get(); - - /* auto rate_bundler = [&event_timestamp_registry, - &total_time_in_seconds](nlohmann::json& jf_evt, const std::string& event_type, const std::string& previous_event) { - if (event_timestamp_registry.count(previous_event) != 0) - { - std::int64_t ts = event_timestamp_registry.at(previous_event); - jf_evt["started_at"] = ts; - std::int64_t ts2 = jf_evt.at("timestamp").get(); - std::stringstream ss; - sys_time t1{std::chrono::milliseconds{ts}}; - sys_time t2{std::chrono::milliseconds{ts2}}; - double res; - res = (std::chrono::duration_cast(t2 - t1).count() / 1000.0); - ss << std::fixed << std::setprecision(3) << res; - jf_evt["time_difference_gui"] = ss.str() + "s"; - event_timestamp_registry[event_type] = ts2; // Negotiated finished at this time - total_time_in_seconds += res; - } - };*/ - + const nlohmann::json& j_evt = content.at("event"); + auto timestamp = content.at("timestamp").get(); + std::string human_date = to_human_date(timestamp, "%F %T"); + auto evt_type = j_evt.at("type").get(); + + auto rate_bundler = [&event_timestamp_registry, + &total_time_in_ms](nlohmann::json& jf_evt, const std::string& event_type, const std::string& previous_event) { + if (event_timestamp_registry.count(previous_event) != 0) + { + std::int64_t ts = event_timestamp_registry.at(previous_event); + jf_evt["started_at"] = ts; + std::int64_t ts2 = jf_evt.at("timestamp").get(); + sys_time t1{std::chrono::milliseconds{ts}}; + sys_time t2{std::chrono::milliseconds{ts2}}; + double res = std::chrono::duration_cast(t2 - t1).count(); + jf_evt["time_diff"] = res; + event_timestamp_registry[event_type] = ts2; // Negotiated finished at this time + total_time_in_ms += res; + } + }; if (j_evt.count("data") == 0) { nlohmann::json jf_evt = {{"state", evt_type}, {"human_timestamp", human_date}, {"timestamp", timestamp}}; + + if (idx > 0) + { + rate_bundler(jf_evt, evt_type, events[idx - 1].at("event").at("type").get()); + } + contents.events.push_back(jf_evt); } else { + nlohmann::json jf_evt = {{"state", evt_type}, {"human_timestamp", human_date}, {"data", j_evt.at("data")}, {"timestamp", timestamp}}; if (evt_type == "Started") { - j_evt["data"]["started_at"] = j_evt.at("data").at("started_at").get() * 1000; + std::int64_t ts = jf_evt.at("data").at("started_at").get() * 1000; + jf_evt["started_at"] = ts; + std::int64_t ts2 = jf_evt.at("timestamp").get(); + sys_time t1{std::chrono::milliseconds{ts}}; + sys_time t2{std::chrono::milliseconds{ts2}}; + double res = std::chrono::duration_cast(t2 - t1).count(); + jf_evt["time_diff"] = res; + event_timestamp_registry["Started"] = ts2; // Started finished at this time + total_time_in_ms += res; } - nlohmann::json jf_evt = {{"state", evt_type}, {"human_timestamp", human_date}, {"data", j_evt.at("data")}, {"timestamp", timestamp}}; + + if (idx > 0) + { + rate_bundler(jf_evt, evt_type, events[idx - 1].at("event").at("type").get()); + } + contents.events.push_back(jf_evt); } + idx += 1; } + contents.total_time_in_ms = total_time_in_ms; } void diff --git a/src/atomic.dex.mm2.api.hpp b/src/atomic.dex.mm2.api.hpp index b592671d83..656ac4bbab 100644 --- a/src/atomic.dex.mm2.api.hpp +++ b/src/atomic.dex.mm2.api.hpp @@ -662,7 +662,7 @@ namespace mm2::api std::string taker_amount; std::string maker_amount; std::string type; - std::string total_time_in_seconds; + double total_time_in_ms; bool funds_recoverable; }; @@ -694,7 +694,7 @@ namespace mm2::api struct kmd_rewards_info_answer { nlohmann::json result; - int rpc_result_code; + int rpc_result_code; }; kmd_rewards_info_answer rpc_kmd_rewards_info(); From 4625b957a3f4e533085088a2b301fc56024d59c4 Mon Sep 17 00:00:00 2001 From: naezith Date: Sun, 16 Aug 2020 00:00:36 +0300 Subject: [PATCH 339/515] feat(gui): use time_diff, live timer is saved for next event --- .../qml/Exchange/SwapProgress.qml | 69 +++++++------------ 1 file changed, 25 insertions(+), 44 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/SwapProgress.qml b/atomic_qt_design/qml/Exchange/SwapProgress.qml index 77321d51af..c6f68a5aa4 100644 --- a/atomic_qt_design/qml/Exchange/SwapProgress.qml +++ b/atomic_qt_design/qml/Exchange/SwapProgress.qml @@ -10,36 +10,16 @@ ColumnLayout { id: root property var details - // QML Hack to get the events for .events field, because onDetailsChanged is not being triggered - property var details_events: !details ? [] : details.events - - // MM2 data needs some modifications, see onDetails_eventsChanged - property var corrected_events: ([]) - - readonly property var all_events: !details ? [] : has_error_event ? corrected_events.map(e => e.state) : details.success_events - - onDetails_eventsChanged: { - if(!details_events) return - - let events = General.clone(details_events) - // Set the missing started_at timestamps - for(let i = 0; i < events.length; ++i) { - if(!events[i].started_at) { - if(events[i].data && events[i].data.started_at) - events[i].started_at = events[i].data.started_at - else if(i > 0) - events[i].started_at = events[i - 1].timestamp - } - } + // QML Hack to get the events for .events field, because onDetailsChanged is not being triggered + readonly property var details_events: !details ? [] : details.events - corrected_events = events - } + readonly property var all_events: !details ? [] : has_error_event ? details_events.map(e => e.state) : details.success_events readonly property bool has_error_event: { if(!details) return false - const events = corrected_events + const events = details_events for(let i = events.length - 1; i >= 0; --i) if(details.error_events.indexOf(events[i].state) !== -1) @@ -48,25 +28,23 @@ ColumnLayout { return false } + property double previous_total_time_passed: 0 readonly property double total_time_passed: { if(!details) return 0 - const events = corrected_events + const events = details_events if(events.length === 0) return 0 let sum = 0 - for(let i = 0; i < events.length; ++i) { - const e = events[i] - console.log(i,"index:", e.started_at, e.timestamp, " = ", e.timestamp - e.started_at) - sum += e.timestamp - e.started_at - } + for(let i = 0; i < events.length; ++i) + sum += events[i].time_diff return sum } readonly property int current_event_idx: { if(!details) return -1 - const events = corrected_events + const events = details_events if(events.length === 0) return -1 if(all_events.length === 0) return -1 @@ -87,7 +65,18 @@ ColumnLayout { onTriggered: simulated_time += interval } - onTotal_time_passedChanged: simulated_time = 0 + property string last_uuid + onTotal_time_passedChanged: { + // Reset for different order + if(details.order_id !== last_uuid) simulated_time = 0 + else { + // Subtract the real time from the simulation, and continue + simulated_time = Math.max(0, simulated_time - (total_time_passed - previous_total_time_passed)) + } + + last_uuid = details.order_id + previous_total_time_passed = total_time_passed + } // Title DefaultText { @@ -104,26 +93,18 @@ ColumnLayout { delegate: Item { readonly property var event: { if(!details) return undefined - const idx = corrected_events.map(e => e.state).indexOf(modelData) + const idx = details_events.map(e => e.state).indexOf(modelData) if(idx === -1) return undefined - return corrected_events[idx] - } - - readonly property double time_passed: { - if(is_current_event) return simulated_time - - if(!event || !event.started_at || !event.timestamp) return 0 - - const diff = event.timestamp - event.started_at - - return diff + return details_events[idx] } readonly property bool is_current_event: index === current_event_idx readonly property bool is_active: General.exists(event) || is_current_event + readonly property double time_passed: event ? event.time_diff : is_current_event ? simulated_time : 0 + width: root.width height: 50 From 080c859ca15f633a5a4b6fe1e5482f1173ebeaea Mon Sep 17 00:00:00 2001 From: naezith Date: Sun, 16 Aug 2020 00:12:17 +0300 Subject: [PATCH 340/515] feat(gui): code polish --- atomic_qt_design/qml/Exchange/SwapProgress.qml | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/SwapProgress.qml b/atomic_qt_design/qml/Exchange/SwapProgress.qml index c6f68a5aa4..170be45e85 100644 --- a/atomic_qt_design/qml/Exchange/SwapProgress.qml +++ b/atomic_qt_design/qml/Exchange/SwapProgress.qml @@ -11,15 +11,12 @@ ColumnLayout { property var details - // QML Hack to get the events for .events field, because onDetailsChanged is not being triggered - readonly property var details_events: !details ? [] : details.events - - readonly property var all_events: !details ? [] : has_error_event ? details_events.map(e => e.state) : details.success_events + readonly property var all_events: !details ? [] : has_error_event ? details.events.map(e => e.state) : details.success_events readonly property bool has_error_event: { if(!details) return false - const events = details_events + const events = details.events for(let i = events.length - 1; i >= 0; --i) if(details.error_events.indexOf(events[i].state) !== -1) @@ -32,7 +29,7 @@ ColumnLayout { readonly property double total_time_passed: { if(!details) return 0 - const events = details_events + const events = details.events if(events.length === 0) return 0 let sum = 0 @@ -44,7 +41,7 @@ ColumnLayout { readonly property int current_event_idx: { if(!details) return -1 - const events = details_events + const events = details.events if(events.length === 0) return -1 if(all_events.length === 0) return -1 @@ -93,10 +90,10 @@ ColumnLayout { delegate: Item { readonly property var event: { if(!details) return undefined - const idx = details_events.map(e => e.state).indexOf(modelData) + const idx = details.events.map(e => e.state).indexOf(modelData) if(idx === -1) return undefined - return details_events[idx] + return details.events[idx] } readonly property bool is_current_event: index === current_event_idx From 9157d9555b80ff4784a8a1ef7779abdd5dfd1ed3 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Sat, 15 Aug 2020 23:31:06 +0200 Subject: [PATCH 341/515] feat(details_swap_progress): add average time --- src/atomic.dex.mm2.api.cpp | 21 +++++++++++++++++++++ src/atomic.dex.mm2.api.hpp | 1 + src/atomic.dex.qt.orders.model.cpp | 22 +++------------------- src/atomic.dex.qt.orders.model.hpp | 11 ++--------- 4 files changed, 27 insertions(+), 28 deletions(-) diff --git a/src/atomic.dex.mm2.api.cpp b/src/atomic.dex.mm2.api.cpp index 54b9be0e81..ada5d42bb6 100644 --- a/src/atomic.dex.mm2.api.cpp +++ b/src/atomic.dex.mm2.api.cpp @@ -818,6 +818,27 @@ namespace mm2::api j.at("limit").get_to(results.limit); j.at("skipped").get_to(results.skipped); j.at("total").get_to(results.total); + results.average_events_time = nlohmann::json::object(); + + std::unordered_map> events_time_registry; + for (auto&& cur_swap: results.swaps) + { + for (auto&& cur_event: cur_swap.events) + { + if (cur_event.contains("time_diff")) + { + events_time_registry[cur_event.at("state").get()].push_back(cur_event.at("time_diff").get()); + } + } + } + + for (auto&& [evt_name, values]: events_time_registry) + { + double sum = 0; + for (auto&& cur_value: values) { sum += cur_value; } + double average = sum / values.size(); + results.average_events_time[evt_name] = average; + } } void diff --git a/src/atomic.dex.mm2.api.hpp b/src/atomic.dex.mm2.api.hpp index 656ac4bbab..32fdb5fac4 100644 --- a/src/atomic.dex.mm2.api.hpp +++ b/src/atomic.dex.mm2.api.hpp @@ -675,6 +675,7 @@ namespace mm2::api std::size_t skipped; std::size_t total; std::string raw_result; + nlohmann::json average_events_time; }; void from_json(const nlohmann::json& j, my_recent_swaps_answer_success& results); diff --git a/src/atomic.dex.qt.orders.model.cpp b/src/atomic.dex.qt.orders.model.cpp index b9142f8363..dddbd1697b 100644 --- a/src/atomic.dex.qt.orders.model.cpp +++ b/src/atomic.dex.qt.orders.model.cpp @@ -488,8 +488,6 @@ namespace atomic_dex } } } - // std::unordered_set out; - // std::set_difference(begin(m_orders_id_registry), end(m_orders_id_registry), begin(to_remove), end(to_remove), std::inserter(out, out.begin())); for (auto&& cur_to_remove: to_remove) { m_orders_id_registry.erase(cur_to_remove); } } } @@ -499,6 +497,7 @@ namespace atomic_dex { const auto& mm2_system = this->m_system_manager.get_system(); const auto result = mm2_system.get_swaps(); + this->set_average_events_time_registry(nlohmann_json_object_to_qt_json_object(result.average_events_time)); for (auto&& current_swap: result.swaps) { if (this->m_swaps_id_registry.find(current_swap.uuid) != this->m_swaps_id_registry.end()) @@ -563,21 +562,6 @@ namespace atomic_dex } } // namespace atomic_dex -//! QML Api -namespace atomic_dex -{ - void - orders_model::save_event_time(const QString& uuid, const QString& event_name, double time) - { - m_events_time_registry[uuid][event_name] = time; - double average = std::accumulate( - begin(m_events_time_registry), end(m_events_time_registry), 0.0, - [event_name](double accumulator, auto&& cur) { return accumulator + cur.second[event_name]; }) / - m_events_time_registry[uuid].size(); - set_average_events_time_registry(event_name, average); - } -} // namespace atomic_dex - namespace atomic_dex { QVariant @@ -587,9 +571,9 @@ namespace atomic_dex } void - atomic_dex::orders_model::set_average_events_time_registry(const QString& event_name, double time) noexcept + atomic_dex::orders_model::set_average_events_time_registry(const QVariant& average_time_registry) noexcept { - m_json_time_registry[event_name] = time; + m_json_time_registry = average_time_registry; emit onAverageEventsTimeRegistryChanged(); } } \ No newline at end of file diff --git a/src/atomic.dex.qt.orders.model.hpp b/src/atomic.dex.qt.orders.model.hpp index 3eaac06ce5..5325b08789 100644 --- a/src/atomic.dex.qt.orders.model.hpp +++ b/src/atomic.dex.qt.orders.model.hpp @@ -84,31 +84,24 @@ namespace atomic_dex [[nodiscard]] orders_proxy_model* get_orders_proxy_mdl() const noexcept; [[nodiscard]] QVariant get_average_events_time_registry() const noexcept; - - //! QML API - Q_INVOKABLE void save_event_time(const QString& uuid, const QString& event_name, double time); - signals: void lengthChanged(); void ordersProxyChanged(); void onAverageEventsTimeRegistryChanged(); private: - void set_average_events_time_registry(const QString& event_name, double time) noexcept; - + void set_average_events_time_registry(const QVariant& average_time_registry) noexcept; ag::ecs::system_manager& m_system_manager; entt::dispatcher& m_dispatcher; using t_orders_datas = QVector; using t_orders_id_registry = std::unordered_set; using t_swaps_id_registry = std::unordered_set; - using t_time_events_registry = std::unordered_map>; t_orders_id_registry m_orders_id_registry; t_swaps_id_registry m_swaps_id_registry; t_orders_datas m_model_data; - t_time_events_registry m_events_time_registry; - QJsonObject m_json_time_registry; + QVariant m_json_time_registry; orders_proxy_model* m_model_proxy; From 8cdcf5c3cc88ede31746b3eb44a570e1008f6d09 Mon Sep 17 00:00:00 2001 From: naezith Date: Sun, 16 Aug 2020 01:33:35 +0300 Subject: [PATCH 342/515] feat(gui): add estimate and colors --- atomic_qt_design/qml/Constants/General.qml | 2 +- atomic_qt_design/qml/Exchange/SwapProgress.qml | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/atomic_qt_design/qml/Constants/General.qml b/atomic_qt_design/qml/Constants/General.qml index 6dab605254..6b9b047c0f 100644 --- a/atomic_qt_design/qml/Constants/General.qml +++ b/atomic_qt_design/qml/Constants/General.qml @@ -76,7 +76,7 @@ QtObject { let seconds = Math.floor(delta / 1000) % 60 delta -= seconds * 1000 - let milliseconds = delta + let milliseconds = Math.floor(delta) return { days, hours, minutes, seconds, milliseconds } } diff --git a/atomic_qt_design/qml/Exchange/SwapProgress.qml b/atomic_qt_design/qml/Exchange/SwapProgress.qml index 170be45e85..2ed080e3d5 100644 --- a/atomic_qt_design/qml/Exchange/SwapProgress.qml +++ b/atomic_qt_design/qml/Exchange/SwapProgress.qml @@ -77,7 +77,10 @@ ColumnLayout { // Title DefaultText { - text_value: API.get().settings_pg.empty_string + (qsTr("Progress details") + " | " + General.durationTextShort(total_time_passed + simulated_time)) + text_value: API.get().settings_pg.empty_string + ( + `` + qsTr("Progress details") + `` + + ` | ` + + `` + General.durationTextShort(total_time_passed + simulated_time) + ``) font.pixelSize: Style.textSize1 Layout.bottomMargin: 10 } @@ -167,8 +170,12 @@ ColumnLayout { visible: bar.visible font.pixelSize: Style.textSizeSmall2 - text_value: API.get().settings_pg.empty_string + (is_active ? General.durationTextShort(time_passed) : '') - color: Style.colorGreen + text_value: API.get().settings_pg.empty_string + (!is_active ? '' : + `` + qsTr("act", "SHORT FOR ACTUAL TIME") + ": " + `` + + `` + General.durationTextShort(time_passed) + `` + + ` | ` + qsTr("est", "SHORT FOR ESTIMATED") + ": " + + General.durationTextShort(API.get().orders_mdl.average_events_time_registry[modelData]) + `` + ) } } } From 418d1f188dd59ddf713da9e5571dda08e8837769 Mon Sep 17 00:00:00 2001 From: naezith Date: Sun, 16 Aug 2020 01:44:55 +0300 Subject: [PATCH 343/515] feat(gui): return "-" for undefined --- atomic_qt_design/qml/Constants/General.qml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/atomic_qt_design/qml/Constants/General.qml b/atomic_qt_design/qml/Constants/General.qml index 6b9b047c0f..0769a8a3dd 100644 --- a/atomic_qt_design/qml/Constants/General.qml +++ b/atomic_qt_design/qml/Constants/General.qml @@ -95,6 +95,9 @@ QtObject { } function durationTextShort(total) { + if(!General.exists(total)) + return "-" + const r = getDuration(total) r.seconds += r.milliseconds/1000 From a39491153d85fd5b6205f32023ce9f24e2ec6c00 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Sun, 16 Aug 2020 14:01:00 +0200 Subject: [PATCH 344/515] feat(details_swap_progress): add decimal --- src/atomic.dex.mm2.api.cpp | 3 +++ src/atomic.dex.mm2.api.hpp | 1 + src/atomic.dex.pch.hpp | 2 ++ src/atomic.dex.qt.trading.page.cpp | 2 +- 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/atomic.dex.mm2.api.cpp b/src/atomic.dex.mm2.api.cpp index ada5d42bb6..a733825976 100644 --- a/src/atomic.dex.mm2.api.cpp +++ b/src/atomic.dex.mm2.api.cpp @@ -55,6 +55,9 @@ namespace mm2::api { j.at("denom").get_to(cfg.denom); j.at("numer").get_to(cfg.numer); + t_rational rat(boost::multiprecision::cpp_int(cfg.numer), boost::multiprecision::cpp_int(cfg.denom)); + t_float_50 res = rat.convert_to(); + cfg.decimal = res.str(8); } void diff --git a/src/atomic.dex.mm2.api.hpp b/src/atomic.dex.mm2.api.hpp index 32fdb5fac4..f1abb6cd9e 100644 --- a/src/atomic.dex.mm2.api.hpp +++ b/src/atomic.dex.mm2.api.hpp @@ -40,6 +40,7 @@ namespace mm2::api { std::string denom; std::string numer; + std::string decimal; }; void from_json(const nlohmann::json& j, max_taker_vol_answer_success& cfg); diff --git a/src/atomic.dex.pch.hpp b/src/atomic.dex.pch.hpp index 8554972af7..b7b109c715 100644 --- a/src/atomic.dex.pch.hpp +++ b/src/atomic.dex.pch.hpp @@ -126,7 +126,9 @@ namespace folly #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-parameter" #include +#include using t_float_50 = boost::multiprecision::cpp_dec_float_50; +using t_rational = boost::multiprecision::cpp_rational; inline std::string get_formated_float(t_float_50 value) diff --git a/src/atomic.dex.qt.trading.page.cpp b/src/atomic.dex.qt.trading.page.cpp index d81c79015e..92f7f3df9f 100644 --- a/src/atomic.dex.qt.trading.page.cpp +++ b/src/atomic.dex.qt.trading.page.cpp @@ -79,7 +79,7 @@ namespace atomic_dex QJsonObject out{ {"denom", QString::fromStdString(answer.result.value().denom)}, {"numer", QString::fromStdString(answer.result.value().numer)}, - }; + {"decimal", QString::fromStdString(answer.result.value().decimal)}}; return out; } return {}; From 82639e2471874c9b526a268d94c978c0e7c2a9b9 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Sun, 16 Aug 2020 15:37:01 +0200 Subject: [PATCH 345/515] feat(app): better connection --- src/atomic.dex.app.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index 6e6bc08963..b359f1d913 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -422,6 +422,7 @@ namespace atomic_dex { //! This event is called when a call is enabled and cex provider finished fetch datas spdlog::debug("{} l{}", __FUNCTION__, __LINE__); + if (evt.ticker == "BTC") { this->m_btc_fully_enabled = true; @@ -431,11 +432,13 @@ namespace atomic_dex { this->m_kmd_fully_enabled = true; } + + qobject_cast(m_manager_models.at("portfolio"))->initialize_portfolio(evt.ticker); + if (this->m_kmd_fully_enabled && this->m_btc_fully_enabled) { this->set_status("complete"); } - qobject_cast(m_manager_models.at("portfolio"))->initialize_portfolio(evt.ticker); } void From 979be900381aed6e3967460b0fe641c9aecc9cb1 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Sun, 16 Aug 2020 15:55:18 +0200 Subject: [PATCH 346/515] feat(app): better connection --- src/atomic.dex.app.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index b359f1d913..a314bb3794 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -52,7 +52,7 @@ namespace { - constexpr std::size_t g_timeout_q_timer_ms = 100; + constexpr std::size_t g_timeout_q_timer_ms = 30; #if defined(_WIN32) || defined(WIN32) bool @@ -495,12 +495,6 @@ namespace atomic_dex return to_qt_binding(std::move(answer), this, QString::fromStdString(coin.explorer_url[0])); } - /*bool - atomic_dex::application::is_claiming_ready(const QString& ticker) - { - return get_mm2().is_claiming_ready(ticker.toStdString()); - }*/ - QVariant atomic_dex::application::claim_rewards(const QString& ticker) { From 675d3929988a6c5da5e671c655a1558f9f2c9900 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Sun, 16 Aug 2020 17:02:09 +0200 Subject: [PATCH 347/515] feat(orders): base_amount and rel_amount for maker orders flip --- src/atomic.dex.qt.orders.model.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/atomic.dex.qt.orders.model.cpp b/src/atomic.dex.qt.orders.model.cpp index dddbd1697b..e9d6035d1b 100644 --- a/src/atomic.dex.qt.orders.model.cpp +++ b/src/atomic.dex.qt.orders.model.cpp @@ -414,6 +414,8 @@ namespace atomic_dex { data.base_coin = QString::fromStdString(contents.base); data.rel_coin = QString::fromStdString(contents.rel); + data.base_amount = QString::fromStdString(contents.base_amount); + data.rel_amount = QString::fromStdString(contents.rel_amount); } data.ticker_pair = data.base_coin + "/" + data.rel_coin; this->m_orders_id_registry.emplace(contents.order_id); From 0610c66bfb487476a5c93f38cdaca203a581be17 Mon Sep 17 00:00:00 2001 From: naezith Date: Sun, 16 Aug 2020 18:20:07 +0300 Subject: [PATCH 348/515] feat(gui): use get_max_taker_vol instead of get_balance --- atomic_qt_design/qml/Exchange/Trade/OrderForm.qml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index 4077481c1c..a80bd3d474 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -55,7 +55,9 @@ FloatingBackground { } function getMaxVolume() { - return API.get().get_balance(base_ticker) + if(!General.isFilled(base_ticker)) return "0" + + return API.get().trading_pg.get_max_taker_vol(base_ticker).decimal } function getMaxTradableVolume(set_as_current) { From 988670f3094a5b9016378157b0c33f4ef770c10f Mon Sep 17 00:00:00 2001 From: naezith Date: Sun, 16 Aug 2020 19:18:43 +0300 Subject: [PATCH 349/515] feat(gui): separate milliseconds and seconds --- atomic_qt_design/qml/Constants/General.qml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/atomic_qt_design/qml/Constants/General.qml b/atomic_qt_design/qml/Constants/General.qml index 0769a8a3dd..d666600731 100644 --- a/atomic_qt_design/qml/Constants/General.qml +++ b/atomic_qt_design/qml/Constants/General.qml @@ -100,13 +100,12 @@ QtObject { const r = getDuration(total) - r.seconds += r.milliseconds/1000 - let text = "" if(r.days > 0) text += qsTr("%nd", "day", r.days) + " " if(r.hours > 0) text += qsTr("%nh", "hours", r.hours) + " " if(r.minutes > 0) text += qsTr("%nm", "minutes", r.minutes) + " " - if(r.seconds > 0) text += qsTr("%1s", "seconds").arg(General.formatDouble(r.seconds, 3)) + " " + if(r.seconds > 0) text += qsTr("%ns", "seconds", r.seconds) + " " + if(r.milliseconds > 0) text += qsTr("%nms", "milliseconds", r.milliseconds) + " " if(text === "") text += qsTr("Instant") return text From 529d9d76d36b8fee771a3aa87757bf4003bde8bd Mon Sep 17 00:00:00 2001 From: naezith Date: Sun, 16 Aug 2020 20:02:59 +0300 Subject: [PATCH 350/515] feat(gui): add estimated total time --- .../qml/Exchange/SwapProgress.qml | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/SwapProgress.qml b/atomic_qt_design/qml/Exchange/SwapProgress.qml index 2ed080e3d5..2140de33c7 100644 --- a/atomic_qt_design/qml/Exchange/SwapProgress.qml +++ b/atomic_qt_design/qml/Exchange/SwapProgress.qml @@ -30,7 +30,6 @@ ColumnLayout { if(!details) return 0 const events = details.events - if(events.length === 0) return 0 let sum = 0 for(let i = 0; i < events.length; ++i) @@ -38,6 +37,15 @@ ColumnLayout { return sum } + readonly property double total_time_passed_estimated: { + const events = all_events + + let sum = 0 + for(let i = 0; i < events.length; ++i) + sum += API.get().orders_mdl.average_events_time_registry[events[i]] + + return sum + } readonly property int current_event_idx: { if(!details) return -1 @@ -62,6 +70,13 @@ ColumnLayout { onTriggered: simulated_time += interval } + function getTimeText(duration, estimated) { + return `` + qsTr("act", "SHORT FOR ACTUAL TIME") + ": " + `` + + `` + General.durationTextShort(duration) + `` + + ` | ` + qsTr("est", "SHORT FOR ESTIMATED") + ": " + + General.durationTextShort(estimated) + `` + } + property string last_uuid onTotal_time_passedChanged: { // Reset for different order @@ -80,7 +95,7 @@ ColumnLayout { text_value: API.get().settings_pg.empty_string + ( `` + qsTr("Progress details") + `` + ` | ` + - `` + General.durationTextShort(total_time_passed + simulated_time) + ``) + getTimeText(total_time_passed + simulated_time, total_time_passed_estimated)) font.pixelSize: Style.textSize1 Layout.bottomMargin: 10 } @@ -170,12 +185,7 @@ ColumnLayout { visible: bar.visible font.pixelSize: Style.textSizeSmall2 - text_value: API.get().settings_pg.empty_string + (!is_active ? '' : - `` + qsTr("act", "SHORT FOR ACTUAL TIME") + ": " + `` + - `` + General.durationTextShort(time_passed) + `` + - ` | ` + qsTr("est", "SHORT FOR ESTIMATED") + ": " + - General.durationTextShort(API.get().orders_mdl.average_events_time_registry[modelData]) + `` - ) + text_value: API.get().settings_pg.empty_string + (!is_active ? '' : getTimeText(time_passed, API.get().orders_mdl.average_events_time_registry[modelData])) } } } From ffc6baee4f7a0b8a9824fc80d123a560054e9bf7 Mon Sep 17 00:00:00 2001 From: naezith Date: Sun, 16 Aug 2020 20:11:24 +0300 Subject: [PATCH 351/515] feat(gui): exclude insignificant ms if > 1s --- atomic_qt_design/qml/Constants/General.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomic_qt_design/qml/Constants/General.qml b/atomic_qt_design/qml/Constants/General.qml index d666600731..5d51f2c80d 100644 --- a/atomic_qt_design/qml/Constants/General.qml +++ b/atomic_qt_design/qml/Constants/General.qml @@ -105,7 +105,7 @@ QtObject { if(r.hours > 0) text += qsTr("%nh", "hours", r.hours) + " " if(r.minutes > 0) text += qsTr("%nm", "minutes", r.minutes) + " " if(r.seconds > 0) text += qsTr("%ns", "seconds", r.seconds) + " " - if(r.milliseconds > 0) text += qsTr("%nms", "milliseconds", r.milliseconds) + " " + if(text === "" && r.milliseconds > 0) text += qsTr("%nms", "milliseconds", r.milliseconds) + " " if(text === "") text += qsTr("Instant") return text From 4fc5071a11139492a8a56f0225ac66319e9c9bfc Mon Sep 17 00:00:00 2001 From: romanszterg Date: Sun, 16 Aug 2020 19:31:34 +0200 Subject: [PATCH 352/515] feat(connection): change login policy --- src/atomic.dex.app.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index a314bb3794..cd8e9b3617 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -52,7 +52,7 @@ namespace { - constexpr std::size_t g_timeout_q_timer_ms = 30; + constexpr std::size_t g_timeout_q_timer_ms = 16; #if defined(_WIN32) || defined(WIN32) bool @@ -435,7 +435,7 @@ namespace atomic_dex qobject_cast(m_manager_models.at("portfolio"))->initialize_portfolio(evt.ticker); - if (this->m_kmd_fully_enabled && this->m_btc_fully_enabled) + if (get_mm2().get_enabled_coins().size() == get_mm2().get_active_coins().size()) { this->set_status("complete"); } From 18ef8aee1123f629767eecb3fa6a010d13c97ee3 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Sun, 16 Aug 2020 20:39:25 +0200 Subject: [PATCH 353/515] feat(max_taker_vol): as property --- src/atomic.dex.mm2.cpp | 30 ++++++++++++++++++++++++++++-- src/atomic.dex.mm2.hpp | 29 ++++++++++++++++++----------- src/atomic.dex.qt.orderbook.cpp | 28 ++++++++++++++++++++++++++++ src/atomic.dex.qt.orderbook.hpp | 17 ++++++++++++++--- 4 files changed, 88 insertions(+), 16 deletions(-) diff --git a/src/atomic.dex.mm2.cpp b/src/atomic.dex.mm2.cpp index 825a073fa2..aa28870f15 100644 --- a/src/atomic.dex.mm2.cpp +++ b/src/atomic.dex.mm2.cpp @@ -515,11 +515,31 @@ namespace atomic_dex mm2::process_orderbook(bool is_a_reset) { auto&& [base, rel] = m_synchronized_ticker_pair.get(); - t_orderbook_request request{.base = base, .rel = rel}; - auto answer = rpc_orderbook(std::move(request)); + t_orderbook_request request{.base = base, .rel = rel}; + ::mm2::api::max_taker_vol_request req_base{.coin = base}; + ::mm2::api::max_taker_vol_request req_rel{.coin = rel}; + std::array, 2> futures; + + futures[0] = spawn([&req_base, this]() { + auto answer = ::mm2::api::rpc_max_taker_vol(std::move(req_base)); + if (answer.rpc_result_code not_eq -1) + { + this->m_synchronized_max_taker_vol->first = answer.result.value(); + } + }); + + futures[1] = spawn([&req_rel, this]() { + auto answer = ::mm2::api::rpc_max_taker_vol(std::move(req_rel)); + if (answer.rpc_result_code not_eq -1) + { + this->m_synchronized_max_taker_vol->second = answer.result.value(); + } + }); + auto answer = rpc_orderbook(std::move(request)); if (answer.rpc_result_code not_eq -1) { m_current_orderbook.insert_or_assign(base + "/" + rel, answer); + for (auto&& fut: futures) { fut.wait(); } this->dispatcher_.trigger(is_a_reset); } } @@ -1149,4 +1169,10 @@ namespace atomic_dex } return nlohmann::json::object(); } + + mm2::t_pair_max_vol + mm2::get_taker_vol() const noexcept + { + return m_synchronized_max_taker_vol.value(); + } } // namespace atomic_dex diff --git a/src/atomic.dex.mm2.hpp b/src/atomic.dex.mm2.hpp index c2f2dc3f63..5c306efb39 100644 --- a/src/atomic.dex.mm2.hpp +++ b/src/atomic.dex.mm2.hpp @@ -71,24 +71,29 @@ namespace atomic_dex class mm2 final : public ag::ecs::pre_update_system { + public: + using t_pair_max_vol = std::pair<::mm2::api::max_taker_vol_answer_success, ::mm2::api::max_taker_vol_answer_success>; + private: //! Private typedefs - using t_mm2_time_point = std::chrono::high_resolution_clock::time_point; - using t_balance_registry = t_concurrent_reg; - using t_my_orders = t_concurrent_reg; - using t_tx_history_registry = t_concurrent_reg; - using t_tx_state_registry = t_concurrent_reg; - using t_orderbook_registry = t_concurrent_reg; - using t_swaps_registry = t_concurrent_reg; - using t_swaps_avrg_datas = t_concurrent_reg; - using t_fees_registry = t_concurrent_reg; - using t_synchronized_ticker_pair = boost::synchronized_value>; + using t_mm2_time_point = std::chrono::high_resolution_clock::time_point; + using t_balance_registry = t_concurrent_reg; + using t_my_orders = t_concurrent_reg; + using t_tx_history_registry = t_concurrent_reg; + using t_tx_state_registry = t_concurrent_reg; + using t_orderbook_registry = t_concurrent_reg; + using t_swaps_registry = t_concurrent_reg; + using t_swaps_avrg_datas = t_concurrent_reg; + using t_fees_registry = t_concurrent_reg; + using t_synchronized_ticker_pair = boost::synchronized_value>; + using t_synchronized_max_taker_vol = boost::synchronized_value; //! Process reproc::process m_mm2_instance; //! Current orderbook - t_synchronized_ticker_pair m_synchronized_ticker_pair{std::make_pair("KMD", "BTC")}; + t_synchronized_ticker_pair m_synchronized_ticker_pair{std::make_pair("KMD", "BTC")}; + t_synchronized_max_taker_vol m_synchronized_max_taker_vol; //! Timers t_mm2_time_point m_orderbook_clock; @@ -265,6 +270,8 @@ namespace atomic_dex [[nodiscard]] bool is_orderbook_thread_active() const noexcept; [[nodiscard]] nlohmann::json get_raw_mm2_ticker_cfg(const std::string& ticker) const noexcept; + + [[nodiscard]] t_pair_max_vol get_taker_vol() const noexcept; }; } // namespace atomic_dex diff --git a/src/atomic.dex.qt.orderbook.cpp b/src/atomic.dex.qt.orderbook.cpp index 443c112d4e..0c1950ee17 100644 --- a/src/atomic.dex.qt.orderbook.cpp +++ b/src/atomic.dex.qt.orderbook.cpp @@ -15,6 +15,8 @@ ******************************************************************************/ #include "atomic.dex.qt.orderbook.hpp" +#include "atomic.dex.mm2.hpp" +#include "atomic.dex.qt.utilities.hpp" namespace atomic_dex { @@ -50,6 +52,7 @@ namespace atomic_dex spdlog::trace("refresh orderbook"); this->m_asks->refresh_orderbook(answer); this->m_bids->refresh_orderbook(answer); + this->set_both_taker_vol(); } void @@ -58,6 +61,7 @@ namespace atomic_dex spdlog::trace("full reset orderbook"); this->m_asks->reset_orderbook(answer); this->m_bids->reset_orderbook(answer); + this->set_both_taker_vol(); } void @@ -66,4 +70,28 @@ namespace atomic_dex this->m_asks->clear_orderbook(); this->m_bids->clear_orderbook(); } + + QVariant + qt_orderbook_wrapper::get_base_max_taker_vol() const noexcept + { + return m_base_max_taker_vol; + } + + QVariant + qt_orderbook_wrapper::get_rel_max_taker_vol() const noexcept + { + return m_rel_max_taker_vol; + } + + void + atomic_dex::qt_orderbook_wrapper::set_both_taker_vol() + { + auto&& [base, rel] = m_system_manager.get_system().get_taker_vol(); + this->m_base_max_taker_vol = QJsonObject{ + {"denom", QString::fromStdString(base.denom)}, {"numer", QString::fromStdString(base.numer)}, {"decimal", QString::fromStdString(base.decimal)}}; + emit baseMaxTakerVolChanged(); + this->m_rel_max_taker_vol = QJsonObject{ + {"denom", QString::fromStdString(rel.denom)}, {"numer", QString::fromStdString(rel.numer)}, {"decimal", QString::fromStdString(rel.decimal)}}; + emit relMaxTakerVolChanged(); + } } // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.orderbook.hpp b/src/atomic.dex.qt.orderbook.hpp index 0426c0fe0b..efa9fa9c76 100644 --- a/src/atomic.dex.qt.orderbook.hpp +++ b/src/atomic.dex.qt.orderbook.hpp @@ -17,6 +17,7 @@ #pragma once //! QT +#include #include //! PCH @@ -32,24 +33,34 @@ namespace atomic_dex Q_OBJECT Q_PROPERTY(orderbook_model* asks READ get_asks MEMBER m_asks NOTIFY asksChanged) Q_PROPERTY(orderbook_model* bids READ get_bids MEMBER m_bids NOTIFY bidsChanged) + Q_PROPERTY(QVariant base_max_taker_vol READ get_base_max_taker_vol NOTIFY baseMaxTakerVolChanged) + Q_PROPERTY(QVariant rel_max_taker_vol READ get_rel_max_taker_vol NOTIFY relMaxTakerVolChanged) public: qt_orderbook_wrapper(ag::ecs::system_manager& system_manager, QObject* parent = nullptr); ~qt_orderbook_wrapper() noexcept final; public: - void refresh_orderbook(t_orderbook_answer answer); - void reset_orderbook(t_orderbook_answer answer); - void clear_orderbook(); + void refresh_orderbook(t_orderbook_answer answer); + void reset_orderbook(t_orderbook_answer answer); + void clear_orderbook(); [[nodiscard]] orderbook_model* get_asks() const noexcept; [[nodiscard]] orderbook_model* get_bids() const noexcept; + [[nodiscard]] QVariant get_base_max_taker_vol() const noexcept; + [[nodiscard]] QVariant get_rel_max_taker_vol() const noexcept; + signals: void asksChanged(); void bidsChanged(); + void baseMaxTakerVolChanged(); + void relMaxTakerVolChanged(); private: + void set_both_taker_vol(); ag::ecs::system_manager& m_system_manager; orderbook_model* m_asks; orderbook_model* m_bids; + QJsonObject m_base_max_taker_vol; + QJsonObject m_rel_max_taker_vol; }; } // namespace atomic_dex \ No newline at end of file From 18c1a632c2d8c943e7a11e3a95587f7db8ae45e9 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Sun, 16 Aug 2020 20:42:21 +0200 Subject: [PATCH 354/515] feat(max_taker_vol): remove qinvokable --- src/atomic.dex.qt.trading.page.cpp | 16 ---------------- src/atomic.dex.qt.trading.page.hpp | 1 - 2 files changed, 17 deletions(-) diff --git a/src/atomic.dex.qt.trading.page.cpp b/src/atomic.dex.qt.trading.page.cpp index 92f7f3df9f..ebc7611421 100644 --- a/src/atomic.dex.qt.trading.page.cpp +++ b/src/atomic.dex.qt.trading.page.cpp @@ -69,22 +69,6 @@ namespace atomic_dex //! Public QML API namespace atomic_dex { - QVariant - trading_page::get_max_taker_vol(const QString& ticker) const noexcept - { - ::mm2::api::max_taker_vol_request req{.coin = ticker.toStdString()}; - auto answer = ::mm2::api::rpc_max_taker_vol(std::move(req)); - if (answer.result.has_value()) - { - QJsonObject out{ - {"denom", QString::fromStdString(answer.result.value().denom)}, - {"numer", QString::fromStdString(answer.result.value().numer)}, - {"decimal", QString::fromStdString(answer.result.value().decimal)}}; - return out; - } - return {}; - } - QVariant trading_page::get_raw_mm2_coin_cfg(const QString& ticker) const noexcept { diff --git a/src/atomic.dex.qt.trading.page.hpp b/src/atomic.dex.qt.trading.page.hpp index b8b0bd7836..c3c0c61213 100644 --- a/src/atomic.dex.qt.trading.page.hpp +++ b/src/atomic.dex.qt.trading.page.hpp @@ -106,7 +106,6 @@ namespace atomic_dex const QString& price_numer, const QString& rel_nota = "", const QString& rel_confs = ""); Q_INVOKABLE void swap_market_pair(); Q_INVOKABLE QVariant get_raw_mm2_coin_cfg(const QString& ticker) const noexcept; - Q_INVOKABLE QVariant get_max_taker_vol(const QString& ticker) const noexcept; //! Properties [[nodiscard]] qt_orderbook_wrapper* get_orderbook_wrapper() const noexcept; From c58b3c46275630c97f8ff498d522a009ecd24884 Mon Sep 17 00:00:00 2001 From: naezith Date: Sun, 16 Aug 2020 22:07:45 +0300 Subject: [PATCH 355/515] feat(gui): use base_max_taker_vol and fallback to balance --- atomic_qt_design/qml/Exchange/Trade/OrderForm.qml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index a80bd3d474..9f17eb0e7e 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -55,9 +55,17 @@ FloatingBackground { } function getMaxVolume() { - if(!General.isFilled(base_ticker)) return "0" + // base in this orderbook is always the left side, so when it's buy, we want the right side balance (rel in the backend) + const value = is_sell_form ? API.get().trading_pg.orderbook.base_max_taker_vol.decimal : + API.get().trading_pg.orderbook.rel_max_taker_vol.decimal - return API.get().trading_pg.get_max_taker_vol(base_ticker).decimal + if(General.isFilled(value)) + return value + + if(General.isFilled(base_ticker)) + return API.get().get_balance(base_ticker) + + return "0" } function getMaxTradableVolume(set_as_current) { From 34711463504915170fb3a3383c239633ad51b069 Mon Sep 17 00:00:00 2001 From: naezith Date: Sun, 16 Aug 2020 22:21:15 +0300 Subject: [PATCH 356/515] feat(gui): better colors for sell buy togglers --- atomic_qt_design/qml/Exchange/Trade/OrderForm.qml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index 9f17eb0e7e..4fde1c50af 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -193,16 +193,16 @@ FloatingBackground { DefaultButton { font.pixelSize: Style.textSize text: API.get().settings_pg.empty_string + (qsTr("Sell")) - color: sell_mode ? Style.colorRed : Style.colorRed3 - colorTextEnabled: sell_mode ? Style.colorWhite1 : Style.colorWhite6 + color: sell_mode ? Style.colorButtonEnabled.danger : Style.colorButtonDisabled.danger + colorTextEnabled: sell_mode ? Style.colorButtonTextEnabled.danger : Style.colorButtonTextDisabled.danger font.weight: Font.Bold onClicked: sell_mode = true } DefaultButton { font.pixelSize: Style.textSize text: API.get().settings_pg.empty_string + (qsTr("Buy")) - color: sell_mode ? Style.colorGreen3 : Style.colorGreen - colorTextEnabled: sell_mode ? Style.colorWhite8 : Style.colorWhite1 + color: sell_mode ? Style.colorButtonDisabled.primary : Style.colorButtonEnabled.primary + colorTextEnabled: sell_mode ? Style.colorButtonTextDisabled.primary : Style.colorButtonTextEnabled.primary font.weight: Font.Bold onClicked: sell_mode = false } From 92b702e1ce95ee8b6c2d057548644e541fbb8155 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Mon, 17 Aug 2020 11:00:19 +0200 Subject: [PATCH 357/515] feat(cfg): add tx url in cfg --- src/atomic.dex.coins.config.cpp | 8 ++++++++ src/atomic.dex.coins.config.hpp | 2 ++ 2 files changed, 10 insertions(+) diff --git a/src/atomic.dex.coins.config.cpp b/src/atomic.dex.coins.config.cpp index 7bb758ed6c..ea27153126 100644 --- a/src/atomic.dex.coins.config.cpp +++ b/src/atomic.dex.coins.config.cpp @@ -71,5 +71,13 @@ namespace atomic_dex j.at("coinpaprika_id").get_to(cfg.coinpaprika_id); j.at("is_erc_20").get_to(cfg.is_erc_20); j.at("explorer_url").get_to(cfg.explorer_url); + if (j.contains("explorer_tx_url")) + { + j.at("explorer_tx_url").get_to(cfg.tx_uri); + } + if (j.contains("explorer_address_url")) + { + j.at("explorer_address_url").get_to(cfg.address_url); + } } } // namespace atomic_dex diff --git a/src/atomic.dex.coins.config.hpp b/src/atomic.dex.coins.config.hpp index 9d7aeba097..97d53ec572 100644 --- a/src/atomic.dex.coins.config.hpp +++ b/src/atomic.dex.coins.config.hpp @@ -51,6 +51,8 @@ namespace atomic_dex bool is_erc_20{false}; std::string type; std::vector explorer_url; ///< usefull for transaction, take this url and append transaction id + std::string tx_uri{"tx"}; + std::string address_url; }; void from_json(const nlohmann::json& j, coin_config& cfg); From 69f249f8a16f3a24ee608256995be111cb9ae720 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Mon, 17 Aug 2020 12:30:35 +0200 Subject: [PATCH 358/515] feat(proxy mdl): separate into a system --- CMakeLists.txt | 1 + .../assets/languages/atomic_qt_en.ts | 350 ++++++++++++++---- .../assets/languages/atomic_qt_fr.ts | 348 +++++++++++++---- .../assets/languages/atomic_qt_tr.ts | 342 +++++++++++++---- .../qml/Components/ColumnHeader.qml | 8 +- atomic_qt_design/qml/Portfolio/Portfolio.qml | 2 +- atomic_qt_design/qml/Screens/Dashboard.qml | 2 +- .../qml/Screens/InitialLoading.qml | 4 +- src/atomic.dex.app.cpp | 40 +- src/atomic.dex.app.hpp | 12 +- src/atomic.dex.qt.portfolio.model.cpp | 8 +- src/atomic.dex.qt.portfolio.model.hpp | 1 + src/atomic.dex.qt.portfolio.page.cpp | 42 +++ src/atomic.dex.qt.portfolio.page.hpp | 58 +++ 14 files changed, 979 insertions(+), 239 deletions(-) create mode 100644 src/atomic.dex.qt.portfolio.page.cpp create mode 100644 src/atomic.dex.qt.portfolio.page.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index bd49d15c0f..e60717177b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -170,6 +170,7 @@ target_sources(atomic_qt_shared_deps INTERFACE ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.orderbook.model.cpp ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.orderbook.proxy.model.cpp ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.portfolio.model.cpp + ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.portfolio.page.cpp ${CMAKE_SOURCE_DIR}/src/atomic.dex.qt.portfolio.proxy.filter.model.cpp $<$:${CMAKE_SOURCE_DIR}/src/osx/atomic.dex.osx.manager.mm> ${CMAKE_SOURCE_DIR}/qml.qrc diff --git a/atomic_qt_design/assets/languages/atomic_qt_en.ts b/atomic_qt_design/assets/languages/atomic_qt_en.ts index 2b08ae8029..8c129439ea 100644 --- a/atomic_qt_design/assets/languages/atomic_qt_en.ts +++ b/atomic_qt_design/assets/languages/atomic_qt_en.ts @@ -50,109 +50,124 @@ ClaimRewardsModal - + Failed to prepare to claim rewards - + Failed to get the rewards info - + Claim your %1 reward? TICKER - + + No UTXOs eligible for claiming + + + + You will receive %1 AMT TICKER - + Transaction fee is higher than the reward! + Refresh + + + + + Read more about KMD active users rewards + + + + UTXO - + Amount - + Reward - - Accruing Start At + + Accruing Stop At - - Accruing Stop At + + Accruing Started At - - Time Left (d:hh:mm:ss) + + Time Left - + Error - + Locktime is not set - + Locktime is less than the threshold - + UTXO height is greater than end of the era - + UTXO amount is less than 10 - + One hour did not pass yet - + Transaction is in mempool - + Unknown problem - + Cancel - + Confirm @@ -184,6 +199,12 @@ dPoW protected + + + + Read more about dPoW + + Use custom protection settings for incoming %1 transactions @@ -195,12 +216,6 @@ Enable Komodo dPoW security - - - - <a href="https://komodoplatform.com/security-delayed-proof-of-work-dpow/">Read more about dPoW</a> - - %1 confirmations for incoming %2 transactions @@ -254,7 +269,7 @@ - Markets data (prices, charts, etc.) marked with the ⓘ icon originates from third party sources. (<a href="https://coinpaprika.com">coinpaprika.com</a>) + Markets data (prices, charts, etc.) marked with the ⓘ icon originates from third party sources. @@ -463,6 +478,116 @@ Unknown State + + + Started + + + + + Negotiated + + + + + Taker fee sent + + + + + Maker payment received + + + + + Maker payment wait confirm started + + + + + Maker payment validated and confirmed + + + + + Taker payment sent + + + + + Taker payment spent + + + + + Maker payment spent + + + + + Finished + + + + + Start failed + + + + + Negotiate failed + + + + + Taker fee validate failed + + + + + Maker payment transaction failed + + + + + Maker payment Data send failed + + + + + Maker payment wait confirm failed + + + + + Taker payment validate failed + + + + + Taker payment wait confirm failed + + + + + Taker payment spend failed + + + + + Maker payment wait refund started + + + + + Maker payment refunded + + + + + Maker payment refund failed + + FirstLaunch @@ -487,6 +612,67 @@ + + General + + + %n day(s) + + + + + + + + %nd + day + + + + + + + + %nh + hours + + + + + + + + %nm + minutes + + + + + + + + %ns + seconds + + + + + + + + %nms + milliseconds + + + + + + + + Instant + + + History @@ -522,6 +708,11 @@ Complete + + + Getting ready + + Languages @@ -609,22 +800,22 @@ - + Loading - + Scanning blocks for TX History... - + Syncing TX History... - + No transactions @@ -801,78 +992,78 @@ OrderForm - + Sell - + Amount to sell - + Amount to receive - + Buy - + Price - + Volume - + Min - + Half - + Max - + Transaction Fee - + Trading Fee - + Fees will be calculated - + Total - + Sell %1 TICKER - + Buy %1 TICKER @@ -889,87 +1080,87 @@ OrderModal - + Swap Details - + Order Details - + Maker Order - + Taker Order - + Refund State - + Your swap failed but the auto-refund process for your payment started already. Please wait and keep application opened until you receive your payment back - + Date - + Maker Payment Sent ID - + Maker Payment Spent ID - + Taker Payment Spent ID - + Taker Payment Sent ID - + Cancel Order - + Error ID - + ID - + Error Log - + Close - + View at Explorer @@ -1126,12 +1317,7 @@ - - Loading - - - - + Disable %1 TICKER @@ -1575,6 +1761,26 @@ + + SwapProgress + + + act + SHORT FOR ACTUAL TIME + + + + + est + SHORT FOR ESTIMATED + + + + + Progress details + + + TextFieldWithTitle diff --git a/atomic_qt_design/assets/languages/atomic_qt_fr.ts b/atomic_qt_design/assets/languages/atomic_qt_fr.ts index 0577fd48ff..75b6b95344 100644 --- a/atomic_qt_design/assets/languages/atomic_qt_fr.ts +++ b/atomic_qt_design/assets/languages/atomic_qt_fr.ts @@ -57,109 +57,124 @@ ClaimRewardsModal - + Failed to prepare to claim rewards - + Failed to get the rewards info - + Claim your %1 reward? TICKER Réclamer votre %1 récompense ? - + + No UTXOs eligible for claiming + + + + You will receive %1 AMT TICKER Vous allez recevoir %1 - + Transaction fee is higher than the reward! + Refresh + + + + + Read more about KMD active users rewards + + + + UTXO - + Amount Montant - + Reward - - Accruing Start At + + Accruing Stop At - - Accruing Stop At + + Accruing Started At - - Time Left (d:hh:mm:ss) + + Time Left - + Error - + Locktime is not set - + Locktime is less than the threshold - + UTXO height is greater than end of the era - + UTXO amount is less than 10 - + One hour did not pass yet - + Transaction is in mempool - + Unknown problem - + Cancel Annuler - + Confirm Confirmer @@ -191,6 +206,12 @@ dPoW protected + + + + Read more about dPoW + + Use custom protection settings for incoming %1 transactions @@ -202,12 +223,6 @@ Enable Komodo dPoW security - - - - <a href="https://komodoplatform.com/security-delayed-proof-of-work-dpow/">Read more about dPoW</a> - - %1 confirmations for incoming %2 transactions @@ -265,7 +280,7 @@ - Markets data (prices, charts, etc.) marked with the ⓘ icon originates from third party sources. (<a href="https://coinpaprika.com">coinpaprika.com</a>) + Markets data (prices, charts, etc.) marked with the ⓘ icon originates from third party sources. @@ -478,6 +493,116 @@ Unknown State + + + Started + + + + + Negotiated + + + + + Taker fee sent + + + + + Maker payment received + + + + + Maker payment wait confirm started + + + + + Maker payment validated and confirmed + + + + + Taker payment sent + + + + + Taker payment spent + + + + + Maker payment spent + + + + + Finished + + + + + Start failed + + + + + Negotiate failed + + + + + Taker fee validate failed + + + + + Maker payment transaction failed + + + + + Maker payment Data send failed + + + + + Maker payment wait confirm failed + + + + + Taker payment validate failed + + + + + Taker payment wait confirm failed + + + + + Taker payment spend failed + + + + + Maker payment wait refund started + + + + + Maker payment refunded + + + + + Maker payment refund failed + + FirstLaunch @@ -506,6 +631,67 @@ Portefeuilles + + General + + + %n day(s) + + + + + + + + %nd + day + + + + + + + + %nh + hours + + + + + + + + %nm + minutes + + + + + + + + %ns + seconds + + + + + + + + %nms + milliseconds + + + + + + + + Instant + + + History @@ -541,6 +727,11 @@ Complete Terminer + + + Getting ready + + Languages @@ -628,22 +819,22 @@ Réclamer des récompenses - + Loading Chargement - + Scanning blocks for TX History... - + Syncing TX History... - + No transactions Pas de transactions @@ -832,7 +1023,7 @@ OrderForm - + Sell Vendre @@ -849,12 +1040,12 @@ Montant - + Amount to sell Montant à vendre - + Amount to receive Montant à recevoir @@ -863,63 +1054,63 @@ Veuillez remplir le montant de la vente - + Buy - + Price Prix - + Volume Volume - + Min - + Half - + Max - + Transaction Fee Frais de transactions - + Trading Fee Frais d'échanges - + Fees will be calculated - + Total - + Sell %1 TICKER - + Buy %1 TICKER @@ -963,42 +1154,42 @@ OrderModal - + Swap Details Détails de l'échange - + Order Details Détails de l'ordre - + Maker Order Ordre de vente - + Taker Order Ordre d'achat - + Refund State - + Your swap failed but the auto-refund process for your payment started already. Please wait and keep application opened until you receive your payment back - + Date Date - + ID @@ -1011,27 +1202,27 @@ UUID - + Maker Payment Sent ID - + Maker Payment Spent ID - + Taker Payment Spent ID - + Taker Payment Sent ID - + Cancel Order @@ -1044,17 +1235,17 @@ ID du paiement du vendeur - + Error ID ID de l'erreur - + Error Log Journal des erreurs - + Close Fermer @@ -1063,7 +1254,7 @@ Annuler - + View at Explorer Voir dans l'explorateur @@ -1273,12 +1464,11 @@ Prix - Loading - Chargement + Chargement - + Disable %1 TICKER Désactivez %1 @@ -1758,6 +1948,26 @@ Vous n'avez pas d'ordres récents. + + SwapProgress + + + act + SHORT FOR ACTUAL TIME + + + + + est + SHORT FOR ESTIMATED + + + + + Progress details + + + TextFieldWithTitle diff --git a/atomic_qt_design/assets/languages/atomic_qt_tr.ts b/atomic_qt_design/assets/languages/atomic_qt_tr.ts index 986e9c0dda..3cdbf1bad8 100644 --- a/atomic_qt_design/assets/languages/atomic_qt_tr.ts +++ b/atomic_qt_design/assets/languages/atomic_qt_tr.ts @@ -61,109 +61,124 @@ ClaimRewardsModal - + Failed to prepare to claim rewards - + Failed to get the rewards info - + Claim your %1 reward? TICKER %1 ödülünüzü alacak mısınız? - + + No UTXOs eligible for claiming + + + + You will receive %1 AMT TICKER %1 alacaksınız - + Transaction fee is higher than the reward! + Refresh + + + + + Read more about KMD active users rewards + + + + UTXO - + Amount Miktar - + Reward - - Accruing Start At + + Accruing Stop At - - Accruing Stop At + + Accruing Started At - - Time Left (d:hh:mm:ss) + + Time Left - + Error - + Locktime is not set - + Locktime is less than the threshold - + UTXO height is greater than end of the era - + UTXO amount is less than 10 - + One hour did not pass yet - + Transaction is in mempool - + Unknown problem - + Cancel İptal - + Confirm Onayla @@ -195,6 +210,12 @@ dPoW protected + + + + Read more about dPoW + + Use custom protection settings for incoming %1 transactions @@ -206,12 +227,6 @@ Enable Komodo dPoW security - - - - <a href="https://komodoplatform.com/security-delayed-proof-of-work-dpow/">Read more about dPoW</a> - - %1 confirmations for incoming %2 transactions @@ -269,7 +284,7 @@ - Markets data (prices, charts, etc.) marked with the ⓘ icon originates from third party sources. (<a href="https://coinpaprika.com">coinpaprika.com</a>) + Markets data (prices, charts, etc.) marked with the ⓘ icon originates from third party sources. @@ -482,6 +497,116 @@ Unknown State + + + Started + + + + + Negotiated + + + + + Taker fee sent + + + + + Maker payment received + + + + + Maker payment wait confirm started + + + + + Maker payment validated and confirmed + + + + + Taker payment sent + + + + + Taker payment spent + + + + + Maker payment spent + + + + + Finished + + + + + Start failed + + + + + Negotiate failed + + + + + Taker fee validate failed + + + + + Maker payment transaction failed + + + + + Maker payment Data send failed + + + + + Maker payment wait confirm failed + + + + + Taker payment validate failed + + + + + Taker payment wait confirm failed + + + + + Taker payment spend failed + + + + + Maker payment wait refund started + + + + + Maker payment refunded + + + + + Maker payment refund failed + + FirstLaunch @@ -510,6 +635,61 @@ Cüzdanlar + + General + + + %n day(s) + + + + + + + %nd + day + + + + + + + %nh + hours + + + + + + + %nm + minutes + + + + + + + %ns + seconds + + + + + + + %nms + milliseconds + + + + + + + Instant + + + History @@ -545,6 +725,11 @@ Complete Tamamlandı + + + Getting ready + + Languages @@ -632,22 +817,22 @@ Ödül Al - + Loading Yükleniyor - + Scanning blocks for TX History... - + Syncing TX History... - + No transactions İşlem yok @@ -834,7 +1019,7 @@ OrderForm - + Sell Satılacak @@ -851,12 +1036,12 @@ Miktar - + Amount to sell Satılacak miktar - + Amount to receive Alınacak miktar @@ -865,63 +1050,63 @@ Lütfen gönderilecek miktarı giriniz - + Buy - + Price Fiyat - + Volume Hacim - + Min - + Half - + Max - + Transaction Fee İşlem Ücreti - + Trading Fee Al-Sat Ücreti - + Fees will be calculated - + Total - + Sell %1 TICKER - + Buy %1 TICKER @@ -965,42 +1150,42 @@ OrderModal - + Swap Details Takas Detayları - + Order Details Emir Detayları - + Maker Order Satıcı Emri - + Taker Order Alıcı Emri - + Refund State - + Your swap failed but the auto-refund process for your payment started already. Please wait and keep application opened until you receive your payment back - + Date Tarih - + ID @@ -1013,27 +1198,27 @@ UUID - + Maker Payment Sent ID - + Maker Payment Spent ID - + Taker Payment Spent ID - + Taker Payment Sent ID - + Cancel Order @@ -1046,17 +1231,17 @@ Alıcı Ödeme ID - + Error ID Hata ID - + Error Log Hata Kaydı - + Close Kapat @@ -1065,7 +1250,7 @@ İptal - + View at Explorer Explorer'da Görüntüle @@ -1274,12 +1459,11 @@ Fiyat - Loading - Yükleniyor + Yükleniyor - + Disable %1 TICKER %1'i Etkinsizleştir @@ -1763,6 +1947,26 @@ Yakın zamanda bir emriniz yok. + + SwapProgress + + + act + SHORT FOR ACTUAL TIME + + + + + est + SHORT FOR ESTIMATED + + + + + Progress details + + + TextFieldWithTitle diff --git a/atomic_qt_design/qml/Components/ColumnHeader.qml b/atomic_qt_design/qml/Components/ColumnHeader.qml index 0290cb1da0..d24bd0762b 100644 --- a/atomic_qt_design/qml/Components/ColumnHeader.qml +++ b/atomic_qt_design/qml/Components/ColumnHeader.qml @@ -29,11 +29,11 @@ Item { // Apply the sort switch(current_sort) { - case sort_by_name: API.get().portfolio_mdl.portfolio_proxy_mdl.sort_by_name(ascending); break - case sort_by_value: API.get().portfolio_mdl.portfolio_proxy_mdl.sort_by_currency_balance(ascending); break - case sort_by_price: API.get().portfolio_mdl.portfolio_proxy_mdl.sort_by_currency_unit(ascending); break + case sort_by_name: API.get().portfolio_pg.portfolio_mdl.portfolio_proxy_mdl.sort_by_name(ascending); break + case sort_by_value: API.get().portfolio_pg.portfolio_mdl.portfolio_proxy_mdl.sort_by_currency_balance(ascending); break + case sort_by_price: API.get().portfolio_pg.portfolio_mdl.portfolio_proxy_mdl.sort_by_currency_unit(ascending); break case sort_by_trend: - case sort_by_change: API.get().portfolio_mdl.portfolio_proxy_mdl.sort_by_change_last24h(ascending); break + case sort_by_change: API.get().portfolio_pg.portfolio_mdl.portfolio_proxy_mdl.sort_by_change_last24h(ascending); break } } } diff --git a/atomic_qt_design/qml/Portfolio/Portfolio.qml b/atomic_qt_design/qml/Portfolio/Portfolio.qml index c6245e595b..096b4a509e 100644 --- a/atomic_qt_design/qml/Portfolio/Portfolio.qml +++ b/atomic_qt_design/qml/Portfolio/Portfolio.qml @@ -125,7 +125,7 @@ ColumnLayout { selectByMouse: true onTextChanged: { - API.get().portfolio_mdl.portfolio_proxy_mdl.setFilterFixedString(text) + API.get().portfolio_pg.portfolio_mdl.portfolio_proxy_mdl.setFilterFixedString(text) } width: 120 diff --git a/atomic_qt_design/qml/Screens/Dashboard.qml b/atomic_qt_design/qml/Screens/Dashboard.qml index cbed35ff11..7b04e08ef3 100644 --- a/atomic_qt_design/qml/Screens/Dashboard.qml +++ b/atomic_qt_design/qml/Screens/Dashboard.qml @@ -46,7 +46,7 @@ Item { return app.current_page === idx_dashboard } - property var portfolio_coins: API.get().portfolio_mdl.portfolio_proxy_mdl + property var portfolio_coins: API.get().portfolio_pg.portfolio_mdl.portfolio_proxy_mdl onCurrent_pageChanged: { if(prev_page !== current_page) { diff --git a/atomic_qt_design/qml/Screens/InitialLoading.qml b/atomic_qt_design/qml/Screens/InitialLoading.qml index db33e4cb5b..ea091dac89 100644 --- a/atomic_qt_design/qml/Screens/InitialLoading.qml +++ b/atomic_qt_design/qml/Screens/InitialLoading.qml @@ -16,7 +16,7 @@ SetupPage { interval: 64 repeat: true onTriggered: { - if(API.get().initial_loading_status === "complete" && API.get().portfolio_mdl.length >= 2) { + if(API.get().initial_loading_status === "complete" && API.get().portfolio_pg.portfolio_mdl.length >= 2) { running = false onLoaded() } @@ -43,7 +43,7 @@ SetupPage { DefaultText { text_value: API.get().settings_pg.empty_string + ((API.get().initial_loading_status === "initializing_mm2" ? qsTr("Initializing MM2") : API.get().initial_loading_status === "enabling_coins" ? qsTr("Enabling coins") : - API.get().initial_loading_status === "complete" && API.get().portfolio_mdl.length >= 2 ? qsTr("Complete") : qsTr("Getting ready")) + "...") + API.get().initial_loading_status === "complete" && API.get().portfolio_pg.portfolio_mdl.length >= 2 ? qsTr("Complete") : qsTr("Getting ready")) + "...") } } } diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index cd8e9b3617..c45b8c0362 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -135,7 +135,8 @@ namespace atomic_dex application::disable_coins(const QStringList& coins) { std::vector coins_std; - qobject_cast(m_manager_models.at("portfolio"))->disable_coins(coins); + + system_manager_.get_system().get_portfolio()->disable_coins(coins); coins_std.reserve(coins.size()); for (auto&& coin: coins) { coins_std.push_back(coin.toStdString()); } get_mm2().disable_multiple_coins(coins_std); @@ -194,7 +195,9 @@ namespace atomic_dex system_manager_.create_system(mm2_s, system_manager_.get_system().get_cfg()); system_manager_.create_system(mm2_s); - system_manager_.create_system(system_manager_, m_event_actions.at(events_action::about_to_exit_app), get_portfolio(), this); + auto& portfolio_system = system_manager_.create_system(system_manager_, dispatcher_, this); + portfolio_system.get_portfolio()->set_cfg(system_manager_.get_system().get_cfg()); + system_manager_.create_system(system_manager_, m_event_actions.at(events_action::about_to_exit_app), portfolio_system.get_portfolio(), this); connect_signals(); @@ -256,7 +259,7 @@ namespace atomic_dex case action::refresh_portfolio_ticker_balance: if (mm2.is_mm2_running()) { - qobject_cast(m_manager_models.at("portfolio"))->update_balance_values(*m_ticker_balance_to_refresh); + system_manager_.get_system().get_portfolio()->update_balance_values(*m_ticker_balance_to_refresh); } break; case action::post_process_orders_finished: @@ -374,7 +377,7 @@ namespace atomic_dex {"update_needed", false}, {"changelog", ""}, {"current_version", ""}, {"download_url", ""}, {"new_version", ""}, {"rpc_code", 0}, {"status", ""}}), m_coin_info(new current_coin_info(dispatcher_, this)), m_manager_models{ {"addressbook", new addressbook_model(this->m_wallet_manager, this)}, - {"portfolio", new portfolio_model(this->system_manager_, this->dispatcher_, this)}, + //{"portfolio", new portfolio_model(this->system_manager_, this->dispatcher_, this)}, {"orders", new orders_model(this->system_manager_, this->dispatcher_, this)}, {"internet_service", std::addressof(system_manager_.create_system(this))}, @@ -384,11 +387,14 @@ namespace atomic_dex //! MM2 system need to be created before the GUI and give the instance to the gui auto& mm2_system = system_manager_.create_system(); auto& settings_page_system = system_manager_.create_system(m_app, this); - get_portfolio()->set_cfg(settings_page_system.get_cfg()); + auto& portfolio_system = system_manager_.create_system(system_manager_, dispatcher_, this); + portfolio_system.get_portfolio()->set_cfg(settings_page_system.get_cfg()); + //get_portfolio()->set_cfg(settings_page_system.get_cfg()); + system_manager_.create_system(mm2_system, settings_page_system.get_cfg()); system_manager_.create_system(mm2_system); system_manager_.create_system(); - system_manager_.create_system(system_manager_, m_event_actions.at(events_action::about_to_exit_app), get_portfolio(), this); + system_manager_.create_system(system_manager_, m_event_actions.at(events_action::about_to_exit_app), portfolio_system.get_portfolio(), this); connect_signals(); if (is_there_a_default_wallet()) @@ -433,7 +439,7 @@ namespace atomic_dex this->m_kmd_fully_enabled = true; } - qobject_cast(m_manager_models.at("portfolio"))->initialize_portfolio(evt.ticker); + system_manager_.get_system().get_portfolio()->initialize_portfolio(evt.ticker); if (get_mm2().get_enabled_coins().size() == get_mm2().get_active_coins().size()) { @@ -658,11 +664,12 @@ namespace atomic_dex addressbook->removeRows(0, count); } - portfolio_model* portfolio = qobject_cast(m_manager_models.at("portfolio")); - if (auto count = portfolio->rowCount(QModelIndex()); count > 0) - { - portfolio->removeRows(0, count, QModelIndex()); - } + //portfolio_model* portfolio = qobject_cast(m_manager_models.at("portfolio")); + + //if (auto count = portfolio->rowCount(QModelIndex()); count > 0) + //{ + // portfolio->removeRows(0, count, QModelIndex()); + //} orders_model* orders = qobject_cast(m_manager_models.at("orders")); if (auto count = orders->rowCount(QModelIndex()); count > 0) @@ -673,6 +680,7 @@ namespace atomic_dex //! Mark systems system_manager_.mark_system(); + system_manager_.mark_system(); system_manager_.mark_system(); system_manager_.mark_system(); system_manager_.mark_system(); @@ -1037,10 +1045,12 @@ namespace atomic_dex //! Portfolio namespace atomic_dex { - portfolio_model* - application::get_portfolio() const noexcept + portfolio_page* + application::get_portfolio_page() const noexcept { - return qobject_cast(m_manager_models.at("portfolio")); + portfolio_page* ptr = const_cast(std::addressof(system_manager_.get_system())); + assert(ptr != nullptr); + return ptr; } } // namespace atomic_dex diff --git a/src/atomic.dex.app.hpp b/src/atomic.dex.app.hpp index ebf6245421..02fba9ba73 100644 --- a/src/atomic.dex.app.hpp +++ b/src/atomic.dex.app.hpp @@ -42,13 +42,17 @@ #include "atomic.dex.qt.internet.checker.service.hpp" #include "atomic.dex.qt.orderbook.hpp" #include "atomic.dex.qt.orders.model.hpp" -#include "atomic.dex.qt.portfolio.model.hpp" +//#include "atomic.dex.qt.portfolio.model.hpp" +#include "atomic.dex.qt.portfolio.page.hpp" #include "atomic.dex.qt.settings.page.hpp" #include "atomic.dex.qt.trading.page.hpp" #include "atomic.dex.qt.wallet.manager.hpp" namespace ag = antara::gaming; +using portfolio_page_ptr = atomic_dex::portfolio_page*; +Q_DECLARE_METATYPE(portfolio_page_ptr) + namespace atomic_dex { struct application : public QObject, public ag::world::app @@ -62,7 +66,7 @@ namespace atomic_dex Q_PROPERTY(addressbook_model* addressbook_mdl READ get_addressbook NOTIFY addressbookChanged) Q_PROPERTY(orders_model* orders_mdl READ get_orders NOTIFY ordersChanged) Q_PROPERTY(QVariant update_status READ get_update_status NOTIFY updateStatusChanged) - Q_PROPERTY(portfolio_model* portfolio_mdl READ get_portfolio NOTIFY portfolioChanged) + Q_PROPERTY(portfolio_page_ptr portfolio_pg READ get_portfolio_page NOTIFY portfolioPageChanged) Q_PROPERTY(notification_manager* notification_mgr READ get_notification_manager) Q_PROPERTY(internet_service_checker* internet_checker READ get_internet_checker NOTIFY internetCheckerChanged) Q_PROPERTY(trading_page* trading_pg READ get_trading_page NOTIFY tradingPageChanged) @@ -138,7 +142,7 @@ namespace atomic_dex entt::dispatcher& get_dispatcher() noexcept; QObject* get_current_coin_info() const noexcept; addressbook_model* get_addressbook() const noexcept; - portfolio_model* get_portfolio() const noexcept; + portfolio_page* get_portfolio_page() const noexcept; orders_model* get_orders() const noexcept; notification_manager* get_notification_manager() const noexcept; trading_page* get_trading_page() const noexcept; @@ -225,7 +229,7 @@ namespace atomic_dex void onWalletDefaultNameChanged(); void myOrdersUpdated(); void addressbookChanged(); - void portfolioChanged(); + void portfolioPageChanged(); void updateStatusChanged(); void ordersChanged(); void tradingPageChanged(); diff --git a/src/atomic.dex.qt.portfolio.model.cpp b/src/atomic.dex.qt.portfolio.model.cpp index 3e61d1a0c2..109863f2bd 100644 --- a/src/atomic.dex.qt.portfolio.model.cpp +++ b/src/atomic.dex.qt.portfolio.model.cpp @@ -35,12 +35,12 @@ namespace namespace atomic_dex { portfolio_model::portfolio_model(ag::ecs::system_manager& system_manager, entt::dispatcher& dispatcher, QObject* parent) noexcept : - QAbstractListModel(parent), m_system_manager(system_manager), m_model_proxy(new portfolio_proxy_model(this)) + QAbstractListModel(parent), m_system_manager(system_manager), m_dispatcher(dispatcher), m_model_proxy(new portfolio_proxy_model(this)) { spdlog::trace("{} l{} f[{}]", __FUNCTION__, __LINE__, fs::path(__FILE__).filename().string()); spdlog::trace("portfolio model created"); - dispatcher.sink().connect<&portfolio_model::on_update_portfolio_values_event>(*this); + m_dispatcher.sink().connect<&portfolio_model::on_update_portfolio_values_event>(*this); this->m_model_proxy->setSourceModel(this); this->m_model_proxy->setDynamicSortFilter(true); this->m_model_proxy->sort_by_currency_balance(false); @@ -50,6 +50,7 @@ namespace atomic_dex portfolio_model::~portfolio_model() noexcept { + m_dispatcher.sink().disconnect<&portfolio_model::on_update_portfolio_values_event>(*this); spdlog::trace("{} l{} f[{}]", __FUNCTION__, __LINE__, fs::path(__FILE__).filename().string()); spdlog::trace("portfolio model destroyed"); } @@ -57,6 +58,7 @@ namespace atomic_dex void atomic_dex::portfolio_model::initialize_portfolio(std::string ticker) { + spdlog::trace("portfolio init: {}", ticker); const auto& mm2_system = this->m_system_manager.get_system(); const auto& paprika = this->m_system_manager.get_system(); auto coin = mm2_system.get_coin_info(ticker); @@ -80,6 +82,7 @@ namespace atomic_dex data.main_currency_balance.toStdString()); this->m_model_data.push_back(std::move(data)); endInsertRows(); + spdlog::trace("size of the portfolio {}", this->get_length()); emit lengthChanged(); } @@ -272,6 +275,7 @@ namespace atomic_dex void portfolio_model::on_update_portfolio_values_event(const update_portfolio_values&) noexcept { + spdlog::trace("refreshing portfolio values"); this->update_currency_values(); } } // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.portfolio.model.hpp b/src/atomic.dex.qt.portfolio.model.hpp index aad4645e03..204f4db504 100644 --- a/src/atomic.dex.qt.portfolio.model.hpp +++ b/src/atomic.dex.qt.portfolio.model.hpp @@ -90,6 +90,7 @@ namespace atomic_dex private: //! From project ag::ecs::system_manager& m_system_manager; + entt::dispatcher& m_dispatcher; atomic_dex::cfg* m_config; //! Properties diff --git a/src/atomic.dex.qt.portfolio.page.cpp b/src/atomic.dex.qt.portfolio.page.cpp new file mode 100644 index 0000000000..2a30339ece --- /dev/null +++ b/src/atomic.dex.qt.portfolio.page.cpp @@ -0,0 +1,42 @@ +/****************************************************************************** + * Copyright © 2013-2019 The Komodo Platform Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * Komodo Platform software, including this file may be copied, modified, * + * propagated or distributed except according to the terms contained in the * + * LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + +#include + +//! +#include "atomic.dex.qt.portfolio.page.hpp" + +namespace atomic_dex +{ + portfolio_page::portfolio_page(entt::registry& registry, ag::ecs::system_manager& system_manager, entt::dispatcher& dispatcher, QObject* parent) : + QObject(parent), system(registry), m_system_manager(system_manager), m_portfolio_mdl(new portfolio_model(system_manager, dispatcher, nullptr)) + { + emit portfolioChanged(); + } + + portfolio_model* + portfolio_page::get_portfolio() const noexcept + { + return m_portfolio_mdl; + } + + void + portfolio_page::update() noexcept + { + } + + portfolio_page::~portfolio_page() noexcept { delete m_portfolio_mdl; } +} // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.portfolio.page.hpp b/src/atomic.dex.qt.portfolio.page.hpp new file mode 100644 index 0000000000..e81e463b8b --- /dev/null +++ b/src/atomic.dex.qt.portfolio.page.hpp @@ -0,0 +1,58 @@ +/****************************************************************************** + * Copyright © 2013-2019 The Komodo Platform Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * Komodo Platform software, including this file may be copied, modified, * + * propagated or distributed except according to the terms contained in the * + * LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + +#pragma once + +//! QT +#include + +//! PCH +#include "atomic.dex.pch.hpp" + +//! Project headers +#include "atomic.dex.qt.portfolio.model.hpp" + + +namespace atomic_dex +{ + class portfolio_page final : public QObject, public ag::ecs::pre_update_system + { + //! Q_Object definition + Q_OBJECT + + //! Properties + Q_PROPERTY(portfolio_model* portfolio_mdl READ get_portfolio NOTIFY portfolioChanged) + + //! Private members fields + ag::ecs::system_manager& m_system_manager; + portfolio_model* m_portfolio_mdl; + + public: + //! Constructor + explicit portfolio_page(entt::registry& registry, ag::ecs::system_manager& system_manager, entt::dispatcher& dispatcher, QObject* parent = nullptr); + ~portfolio_page() noexcept final; + + //! Public override + void update() noexcept final; + + [[nodiscard]] portfolio_model* get_portfolio() const noexcept; + + signals: + void portfolioChanged(); + }; +} // namespace atomic_dex + +REFL_AUTO(type(atomic_dex::portfolio_page)) \ No newline at end of file From 2b75c9252c3358686472f35b960f7654d2868612 Mon Sep 17 00:00:00 2001 From: naezith Date: Mon, 17 Aug 2020 13:48:40 +0300 Subject: [PATCH 359/515] feat(gui): rename instant to "-" --- atomic_qt_design/qml/Constants/General.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomic_qt_design/qml/Constants/General.qml b/atomic_qt_design/qml/Constants/General.qml index 5d51f2c80d..bc75fcf0dc 100644 --- a/atomic_qt_design/qml/Constants/General.qml +++ b/atomic_qt_design/qml/Constants/General.qml @@ -106,7 +106,7 @@ QtObject { if(r.minutes > 0) text += qsTr("%nm", "minutes", r.minutes) + " " if(r.seconds > 0) text += qsTr("%ns", "seconds", r.seconds) + " " if(text === "" && r.milliseconds > 0) text += qsTr("%nms", "milliseconds", r.milliseconds) + " " - if(text === "") text += qsTr("Instant") + if(text === "") text += qsTr("-") return text } From 83d2a6492602bf6b64549446a20d5d023111b986 Mon Sep 17 00:00:00 2001 From: ca333 Date: Mon, 17 Aug 2020 12:57:08 +0200 Subject: [PATCH 360/515] update dependency src --- ci_tools_atomic_dex/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci_tools_atomic_dex/README.md b/ci_tools_atomic_dex/README.md index 872d65d4af..7970f53466 100644 --- a/ci_tools_atomic_dex/README.md +++ b/ci_tools_atomic_dex/README.md @@ -71,7 +71,7 @@ make install Installling libbitcoin: ``` -git clone --depth 1 --branch version5 --single-branch "https://github.com/libbitcoin/secp256k1" +git clone --depth 1 --branch version5 --single-branch "https://github.com/KomodoPlatform/secp256k1" cd secp256k1 ./autogen.sh ./configure --disable-shared --disable-tests --enable-module-recovery From 3ce156010401168ba535908e730fe2731eb298ac Mon Sep 17 00:00:00 2001 From: romanszterg Date: Mon, 17 Aug 2020 13:31:28 +0200 Subject: [PATCH 361/515] feat(proxy_as_a_system): dont kill system, it's drive QML crazy, just disconnect signals --- src/atomic.dex.app.cpp | 13 ++++++++----- src/atomic.dex.qt.market.pairs.cpp | 7 +++++++ src/atomic.dex.qt.market.pairs.hpp | 1 + src/atomic.dex.qt.portfolio.model.cpp | 14 +++++++++++++- src/atomic.dex.qt.portfolio.model.hpp | 2 ++ src/atomic.dex.qt.portfolio.page.cpp | 4 ++-- src/atomic.dex.qt.portfolio.proxy.filter.model.cpp | 7 +++++++ src/atomic.dex.qt.portfolio.proxy.filter.model.hpp | 2 ++ src/atomic.dex.qt.trading.page.cpp | 6 ++++++ src/atomic.dex.qt.trading.page.hpp | 1 + 10 files changed, 49 insertions(+), 8 deletions(-) diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index c45b8c0362..064151ce94 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -195,9 +195,9 @@ namespace atomic_dex system_manager_.create_system(mm2_s, system_manager_.get_system().get_cfg()); system_manager_.create_system(mm2_s); - auto& portfolio_system = system_manager_.create_system(system_manager_, dispatcher_, this); - portfolio_system.get_portfolio()->set_cfg(system_manager_.get_system().get_cfg()); - system_manager_.create_system(system_manager_, m_event_actions.at(events_action::about_to_exit_app), portfolio_system.get_portfolio(), this); + //auto& portfolio_system = system_manager_.create_system(system_manager_, dispatcher_, this); + //portfolio_system.get_portfolio()->set_cfg(system_manager_.get_system().get_cfg()); + //system_manager_.create_system(system_manager_, m_event_actions.at(events_action::about_to_exit_app), system_manager_.get_system().get_portfolio(), this); connect_signals(); @@ -678,12 +678,15 @@ namespace atomic_dex } orders->clear_registry(); + system_manager_.get_system().get_portfolio()->reset(); + system_manager_.get_system().clear_models(); + //! Mark systems system_manager_.mark_system(); - system_manager_.mark_system(); + //system_manager_.mark_system(); system_manager_.mark_system(); system_manager_.mark_system(); - system_manager_.mark_system(); + //system_manager_.mark_system(); //! Disconnect signals system_manager_.get_system().disconnect_signals(); diff --git a/src/atomic.dex.qt.market.pairs.cpp b/src/atomic.dex.qt.market.pairs.cpp index f0ba5d1bf5..823c6b62bf 100644 --- a/src/atomic.dex.qt.market.pairs.cpp +++ b/src/atomic.dex.qt.market.pairs.cpp @@ -114,6 +114,13 @@ namespace atomic_dex { return m_right_selection_box; } + + void + market_pairs::reset() + { + //m_left_selection_box->reset(); + //m_right_selection_box->reset(); + } } // namespace atomic_dex //! public API diff --git a/src/atomic.dex.qt.market.pairs.hpp b/src/atomic.dex.qt.market.pairs.hpp index 88ec8bbbad..c117426688 100644 --- a/src/atomic.dex.qt.market.pairs.hpp +++ b/src/atomic.dex.qt.market.pairs.hpp @@ -54,6 +54,7 @@ namespace atomic_dex [[nodiscard]] portfolio_proxy_model* get_right_selection_box() const noexcept; void set_left_selected_coin(QString left_coin) noexcept; void set_right_selected_coin(QString right_coin) noexcept; + void reset(); signals: void leftSelectedCoinChanged(); diff --git a/src/atomic.dex.qt.portfolio.model.cpp b/src/atomic.dex.qt.portfolio.model.cpp index 109863f2bd..59336e4a97 100644 --- a/src/atomic.dex.qt.portfolio.model.cpp +++ b/src/atomic.dex.qt.portfolio.model.cpp @@ -15,6 +15,7 @@ ******************************************************************************/ //! Project Headers +#include #include "atomic.dex.qt.portfolio.model.hpp" #include "atomic.dex.qt.utilities.hpp" #include "atomic.threadpool.hpp" @@ -35,7 +36,7 @@ namespace namespace atomic_dex { portfolio_model::portfolio_model(ag::ecs::system_manager& system_manager, entt::dispatcher& dispatcher, QObject* parent) noexcept : - QAbstractListModel(parent), m_system_manager(system_manager), m_dispatcher(dispatcher), m_model_proxy(new portfolio_proxy_model(this)) + QAbstractListModel(parent), m_system_manager(system_manager), m_dispatcher(dispatcher), m_model_proxy(new portfolio_proxy_model(parent)) { spdlog::trace("{} l{} f[{}]", __FUNCTION__, __LINE__, fs::path(__FILE__).filename().string()); spdlog::trace("portfolio model created"); @@ -46,6 +47,9 @@ namespace atomic_dex this->m_model_proxy->sort_by_currency_balance(false); this->m_model_proxy->setFilterRole(NameRole); this->m_model_proxy->setFilterCaseSensitivity(Qt::CaseInsensitive); + + //QQmlEngine::setObjectOwnership(m_model_proxy, QQmlEngine::JavaScriptOwnership); + //emit portfolioProxyChanged(); } portfolio_model::~portfolio_model() noexcept @@ -53,6 +57,7 @@ namespace atomic_dex m_dispatcher.sink().disconnect<&portfolio_model::on_update_portfolio_values_event>(*this); spdlog::trace("{} l{} f[{}]", __FUNCTION__, __LINE__, fs::path(__FILE__).filename().string()); spdlog::trace("portfolio model destroyed"); + //delete m_model_proxy; } void @@ -278,4 +283,11 @@ namespace atomic_dex spdlog::trace("refreshing portfolio values"); this->update_currency_values(); } + void + portfolio_model::reset() + { + this->beginResetModel(); + this->m_model_data.clear(); + this->endResetModel(); + } } // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.portfolio.model.hpp b/src/atomic.dex.qt.portfolio.model.hpp index 204f4db504..e466a26a8a 100644 --- a/src/atomic.dex.qt.portfolio.model.hpp +++ b/src/atomic.dex.qt.portfolio.model.hpp @@ -83,6 +83,8 @@ namespace atomic_dex [[nodiscard]] portfolio_proxy_model* get_portfolio_proxy_mdl() const noexcept; [[nodiscard]] int get_length() const noexcept; + void reset(); + signals: void portfolioProxyChanged(); void lengthChanged(); diff --git a/src/atomic.dex.qt.portfolio.page.cpp b/src/atomic.dex.qt.portfolio.page.cpp index 2a30339ece..2df96b5bb3 100644 --- a/src/atomic.dex.qt.portfolio.page.cpp +++ b/src/atomic.dex.qt.portfolio.page.cpp @@ -22,7 +22,7 @@ namespace atomic_dex { portfolio_page::portfolio_page(entt::registry& registry, ag::ecs::system_manager& system_manager, entt::dispatcher& dispatcher, QObject* parent) : - QObject(parent), system(registry), m_system_manager(system_manager), m_portfolio_mdl(new portfolio_model(system_manager, dispatcher, nullptr)) + QObject(parent), system(registry), m_system_manager(system_manager), m_portfolio_mdl(new portfolio_model(system_manager, dispatcher, this)) { emit portfolioChanged(); } @@ -38,5 +38,5 @@ namespace atomic_dex { } - portfolio_page::~portfolio_page() noexcept { delete m_portfolio_mdl; } + portfolio_page::~portfolio_page() noexcept { /*delete m_portfolio_mdl;*/ } } // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.portfolio.proxy.filter.model.cpp b/src/atomic.dex.qt.portfolio.proxy.filter.model.cpp index fa6efe4395..28ae86546d 100644 --- a/src/atomic.dex.qt.portfolio.proxy.filter.model.cpp +++ b/src/atomic.dex.qt.portfolio.proxy.filter.model.cpp @@ -110,4 +110,11 @@ namespace atomic_dex } return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent); } + + void + portfolio_proxy_model::reset() + { + this->beginResetModel(); + this->endResetModel(); + } } // namespace atomic_dex \ No newline at end of file diff --git a/src/atomic.dex.qt.portfolio.proxy.filter.model.hpp b/src/atomic.dex.qt.portfolio.proxy.filter.model.hpp index f86bf1668b..7f1302845f 100644 --- a/src/atomic.dex.qt.portfolio.proxy.filter.model.hpp +++ b/src/atomic.dex.qt.portfolio.proxy.filter.model.hpp @@ -37,6 +37,8 @@ namespace atomic_dex Q_INVOKABLE void sort_by_change_last24h(bool is_ascending); Q_INVOKABLE void sort_by_currency_unit(bool is_ascending); + void reset(); + protected: //! Override member functions [[nodiscard]] bool lessThan(const QModelIndex& source_left, const QModelIndex& source_right) const final; diff --git a/src/atomic.dex.qt.trading.page.cpp b/src/atomic.dex.qt.trading.page.cpp index ebc7611421..82abad35a0 100644 --- a/src/atomic.dex.qt.trading.page.cpp +++ b/src/atomic.dex.qt.trading.page.cpp @@ -208,6 +208,12 @@ namespace atomic_dex //! Public API namespace atomic_dex { + void + trading_page::clear_models() + { + get_market_pairs_mdl()->reset(); + } + void trading_page::update() noexcept { diff --git a/src/atomic.dex.qt.trading.page.hpp b/src/atomic.dex.qt.trading.page.hpp index c3c0c61213..40bc896b0c 100644 --- a/src/atomic.dex.qt.trading.page.hpp +++ b/src/atomic.dex.qt.trading.page.hpp @@ -90,6 +90,7 @@ namespace atomic_dex void process_action(); void connect_signals(); void disconnect_signals(); + void clear_models(); //! Public QML API Q_INVOKABLE void set_current_orderbook(const QString& base, const QString& rel); From dbfef37e15d1bd1e779196e431e65328a292b71d Mon Sep 17 00:00:00 2001 From: naezith Date: Mon, 17 Aug 2020 14:40:09 +0300 Subject: [PATCH 362/515] feat(gui): repeat orderbook pair initialization at relogin --- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index f502f06ea6..7958d5a574 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -33,6 +33,7 @@ Item { } function fullReset() { + initialized_orderbook_pair = false reset(true) sell_mode = true } From 1def37f101d856e74a60b3a8327add11085a6706 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Mon, 17 Aug 2020 13:51:24 +0200 Subject: [PATCH 363/515] feat(proxy_as_a_system): reset left and right coin --- src/atomic.dex.qt.market.pairs.cpp | 6 ++++-- src/atomic.dex.qt.portfolio.model.cpp | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/atomic.dex.qt.market.pairs.cpp b/src/atomic.dex.qt.market.pairs.cpp index 823c6b62bf..82771e3a01 100644 --- a/src/atomic.dex.qt.market.pairs.cpp +++ b/src/atomic.dex.qt.market.pairs.cpp @@ -118,8 +118,10 @@ namespace atomic_dex void market_pairs::reset() { - //m_left_selection_box->reset(); - //m_right_selection_box->reset(); + this->m_left_selected_coin = ""; + this->m_right_selected_coin = ""; + emit rightSelectedCoinChanged(); + emit leftSelectedCoinChanged(); } } // namespace atomic_dex diff --git a/src/atomic.dex.qt.portfolio.model.cpp b/src/atomic.dex.qt.portfolio.model.cpp index 59336e4a97..dab93f7490 100644 --- a/src/atomic.dex.qt.portfolio.model.cpp +++ b/src/atomic.dex.qt.portfolio.model.cpp @@ -283,6 +283,7 @@ namespace atomic_dex spdlog::trace("refreshing portfolio values"); this->update_currency_values(); } + void portfolio_model::reset() { From 9b16d0aaed624612e9f4b5ae8be94dbf0f727318 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Mon, 17 Aug 2020 13:54:41 +0200 Subject: [PATCH 364/515] feat(proxy_as_a_system): clean code --- src/atomic.dex.app.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index 064151ce94..29f1b53b8a 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -664,13 +664,6 @@ namespace atomic_dex addressbook->removeRows(0, count); } - //portfolio_model* portfolio = qobject_cast(m_manager_models.at("portfolio")); - - //if (auto count = portfolio->rowCount(QModelIndex()); count > 0) - //{ - // portfolio->removeRows(0, count, QModelIndex()); - //} - orders_model* orders = qobject_cast(m_manager_models.at("orders")); if (auto count = orders->rowCount(QModelIndex()); count > 0) { @@ -683,10 +676,8 @@ namespace atomic_dex //! Mark systems system_manager_.mark_system(); - //system_manager_.mark_system(); system_manager_.mark_system(); system_manager_.mark_system(); - //system_manager_.mark_system(); //! Disconnect signals system_manager_.get_system().disconnect_signals(); From 68b96d355d79342f5e3c69509b7230f9a460d34f Mon Sep 17 00:00:00 2001 From: romanszterg Date: Mon, 17 Aug 2020 13:59:34 +0200 Subject: [PATCH 365/515] feat(url): add new url specifier --- src/atomic.dex.coins.config.hpp | 4 ++-- src/atomic.dex.qt.bindings.hpp | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/atomic.dex.coins.config.hpp b/src/atomic.dex.coins.config.hpp index 97d53ec572..e9d53256f6 100644 --- a/src/atomic.dex.coins.config.hpp +++ b/src/atomic.dex.coins.config.hpp @@ -51,8 +51,8 @@ namespace atomic_dex bool is_erc_20{false}; std::string type; std::vector explorer_url; ///< usefull for transaction, take this url and append transaction id - std::string tx_uri{"tx"}; - std::string address_url; + std::string tx_uri{"tx/"}; + std::string address_url{"address/"}; }; void from_json(const nlohmann::json& j, coin_config& cfg); diff --git a/src/atomic.dex.qt.bindings.hpp b/src/atomic.dex.qt.bindings.hpp index 55193cc68d..948b8830ef 100644 --- a/src/atomic.dex.qt.bindings.hpp +++ b/src/atomic.dex.qt.bindings.hpp @@ -53,7 +53,8 @@ namespace atomic_dex Q_PROPERTY(QString fees READ get_fees CONSTANT MEMBER m_fees) Q_PROPERTY(QString explorer_url READ get_explorer_url CONSTANT MEMBER m_explorer_url) - [[nodiscard]] QString get_total_amount() const noexcept + [[nodiscard]] QString + get_total_amount() const noexcept { return m_total_amount; } @@ -149,7 +150,9 @@ namespace atomic_dex {"ticker", coin.ticker}, {"name", coin.name}, {"type", coin.type}, - {"explorer_url", coin.explorer_url}}; + {"explorer_url", coin.explorer_url}, + {"tx_uri", coin.tx_uri}, + {"address_uri", coin.address_url}}; return j; } From 0b0e2f88390bb495be1f1fed56642f495580815c Mon Sep 17 00:00:00 2001 From: naezith Date: Mon, 17 Aug 2020 15:06:14 +0300 Subject: [PATCH 366/515] feat(gui): use tx_uri & address_uri --- atomic_qt_design/qml/Constants/General.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/Constants/General.qml b/atomic_qt_design/qml/Constants/General.qml index bc75fcf0dc..4b49d5217f 100644 --- a/atomic_qt_design/qml/Constants/General.qml +++ b/atomic_qt_design/qml/Constants/General.qml @@ -123,14 +123,14 @@ QtObject { if(id !== '') { const coin_info = API.get().get_coin_info(ticker) const id_prefix = add_0x && coin_info.type === 'ERC-20' ? '0x' : '' - Qt.openUrlExternally(coin_info.explorer_url + 'tx/' + id_prefix + id) + Qt.openUrlExternally(coin_info.tx_uri + id_prefix + id) } } function viewAddressAtExplorer(ticker, address) { if(address !== '') { const coin_info = API.get().get_coin_info(ticker) - Qt.openUrlExternally(coin_info.explorer_url + 'address/' + address) + Qt.openUrlExternally(coin_info.address_uri + address) } } From 5af5c6461864c2a8486f8d54fb7666bda58e6486 Mon Sep 17 00:00:00 2001 From: naezith Date: Mon, 17 Aug 2020 15:08:57 +0300 Subject: [PATCH 367/515] feat(gui): use explorer_url --- atomic_qt_design/qml/Constants/General.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/Constants/General.qml b/atomic_qt_design/qml/Constants/General.qml index 4b49d5217f..4f582a00fc 100644 --- a/atomic_qt_design/qml/Constants/General.qml +++ b/atomic_qt_design/qml/Constants/General.qml @@ -123,14 +123,14 @@ QtObject { if(id !== '') { const coin_info = API.get().get_coin_info(ticker) const id_prefix = add_0x && coin_info.type === 'ERC-20' ? '0x' : '' - Qt.openUrlExternally(coin_info.tx_uri + id_prefix + id) + Qt.openUrlExternally(coin_info.explorer_url + coin_info.tx_uri + id_prefix + id) } } function viewAddressAtExplorer(ticker, address) { if(address !== '') { const coin_info = API.get().get_coin_info(ticker) - Qt.openUrlExternally(coin_info.address_uri + address) + Qt.openUrlExternally(coin_info.explorer_url + coin_info.address_uri + address) } } From 14557a951b2b95e2cda8e5b8c48fbbec9283ac27 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Mon, 17 Aug 2020 15:11:29 +0200 Subject: [PATCH 368/515] feat(wallet): set default to KMD after initialisation --- src/atomic.dex.app.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index 29f1b53b8a..bdcc7c19a3 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -443,6 +443,8 @@ namespace atomic_dex if (get_mm2().get_enabled_coins().size() == get_mm2().get_active_coins().size()) { + m_coin_info->set_ticker("KMD"); + emit coinInfoChanged(); this->set_status("complete"); } } From 5f6f4bbf3a19dd7d69caeeba84a9b1ffda309383 Mon Sep 17 00:00:00 2001 From: naezith Date: Mon, 17 Aug 2020 16:58:45 +0300 Subject: [PATCH 369/515] feat(gui): fix buy side blocking when it shouldn't --- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 2 -- 1 file changed, 2 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index 7958d5a574..f50cebf4af 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -407,8 +407,6 @@ Item { anchors.left: parent.left anchors.right: parent.right anchors.top: parent.top - - field.enabled: form_base.field.enabled } // Show errors From f4acbb139c37349e2804bb8955b89b1b4ce81854 Mon Sep 17 00:00:00 2001 From: naezith Date: Mon, 17 Aug 2020 17:09:34 +0300 Subject: [PATCH 370/515] feat(gui): remove enabled property --- atomic_qt_design/qml/Exchange/Trade/OrderForm.qml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index 4fde1c50af..2436afe3e5 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -12,7 +12,6 @@ FloatingBackground { property alias field: input_volume.field property alias price_field: input_price.field property bool is_sell_form: false - property bool enabled: true property alias column_layout: form_layout property string total_amount: "0" @@ -248,7 +247,7 @@ FloatingBackground { AmountFieldWithInfo { id: input_volume width: parent.width - field.enabled: root.enabled && !shouldBlockInput() + field.enabled: !shouldBlockInput() field.left_text: API.get().settings_pg.empty_string + (qsTr("Volume")) field.right_text: left_ticker From 84cbb6defca9293e083f34c58fa5a40d7ba4aa71 Mon Sep 17 00:00:00 2001 From: naezith Date: Mon, 17 Aug 2020 17:20:51 +0300 Subject: [PATCH 371/515] feat(gui): better errors for trade page --- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index f50cebf4af..2cd4abd82c 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -420,12 +420,26 @@ Item { color: Style.colorRed text_value: API.get().settings_pg.empty_string + ( - General.isZero(getCurrentPrice()) ? (qsTr("Please fill the price field")) : + // Buy side needs the price + (!sell_mode && General.isZero(getCurrentPrice())) ? (qsTr("Please fill the price field")) : + + // Balance check can be done without price too, prioritize that for sell notEnoughBalance() ? (qsTr("%1 balance is lower than minimum trade amount").arg(base_ticker) + " : " + General.getMinTradeAmount()) : + + // Price field comes again + General.isZero(getCurrentPrice()) ? (qsTr("Please fill the price field")) : + + // Fill the volume field + General.isZero(getCurrentForm().getVolume()) ? (qsTr("Please fill the volume field")) : + + // Fields are filled, fee can be checked notEnoughBalanceForFees() ? (qsTr("Not enough balance for the fees. Need at least %1 more", "AMT TICKER").arg(General.formatCrypto("", parseFloat(curr_trade_info.amount_needed), base_ticker))) : - General.isZero(getCurrentForm().getVolume()) ? (qsTr("Please fill the volume field")) : + + // Not enough ETH for fees (getCurrentForm().hasEthFees() && !getCurrentForm().hasEnoughEthForFees()) ? (qsTr("Not enough ETH for the transaction fee")) : + + // Trade amount is lower than the minimum (getCurrentForm().fieldsAreFilled() && !getCurrentForm().higherThanMinTradeAmount()) ? ((qsTr("Amount is lower than minimum trade amount")) + " : " + General.getMinTradeAmount()) : "" ) From 5b2b827ad5747a50b22ed73d4de585704e136777 Mon Sep 17 00:00:00 2001 From: naezith Date: Mon, 17 Aug 2020 17:34:42 +0300 Subject: [PATCH 372/515] feat(gui): more descriptive low balance error --- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index 2cd4abd82c..5dc5e9f26e 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -420,13 +420,10 @@ Item { color: Style.colorRed text_value: API.get().settings_pg.empty_string + ( - // Buy side needs the price - (!sell_mode && General.isZero(getCurrentPrice())) ? (qsTr("Please fill the price field")) : - // Balance check can be done without price too, prioritize that for sell - notEnoughBalance() ? (qsTr("%1 balance is lower than minimum trade amount").arg(base_ticker) + " : " + General.getMinTradeAmount()) : + notEnoughBalance() ? (qsTr("Tradable (after fees) %1 balance is lower than minimum trade amount").arg(base_ticker) + " : " + General.getMinTradeAmount()) : - // Price field comes again + // Fill the price field General.isZero(getCurrentPrice()) ? (qsTr("Please fill the price field")) : // Fill the volume field From f1da5f57d46778d09f5b6284368b286680232fba Mon Sep 17 00:00:00 2001 From: naezith Date: Mon, 17 Aug 2020 17:52:46 +0300 Subject: [PATCH 373/515] feat(gui): clean volume field fully --- atomic_qt_design/qml/Exchange/Trade/OrderForm.qml | 14 +------------- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 4 ++-- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml index 2436afe3e5..0750aabe5d 100644 --- a/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml +++ b/atomic_qt_design/qml/Exchange/Trade/OrderForm.qml @@ -88,19 +88,7 @@ FloatingBackground { function reset(is_base) { input_price.field.text = '' - - if(is_sell_form) { - // is_base info comes from the ComboBox ticker change in OrderForm. - // At other places it's not given. - // We don't want to reset base balance at rel ticker change - // Therefore it will reset only if this info is set from ComboBox -> setPair - // Or if it's from somewhere else like page change, in that case is_base is undefined - if(is_base === undefined || is_base) - input_volume.field.text = General.formatDouble(getMaxTradableVolume(true)) - } - else { - input_volume.field.text = '' - } + input_volume.field.text = '' } function capVolume() { diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index 5dc5e9f26e..f62dc1a22e 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -41,8 +41,8 @@ Item { function reset(reset_result=true, is_base) { if(reset_result) action_result = "" resetPreferredPrice() - form_base.reset(is_base) - form_rel.reset(is_base) + form_base.reset() + form_rel.reset() resetTradeInfo() } From 180985db38e3b2e4435abad9f3fcc568a62ce67f Mon Sep 17 00:00:00 2001 From: romanszterg Date: Mon, 17 Aug 2020 17:16:47 +0200 Subject: [PATCH 374/515] feat(market_pair): sort by alphabetical order --- .../assets/languages/atomic_qt_en.ts | 18 +++++++++--------- .../assets/languages/atomic_qt_fr.ts | 18 +++++++++--------- .../assets/languages/atomic_qt_tr.ts | 18 +++++++++--------- src/atomic.dex.qt.market.pairs.cpp | 4 ++-- 4 files changed, 29 insertions(+), 29 deletions(-) diff --git a/atomic_qt_design/assets/languages/atomic_qt_en.ts b/atomic_qt_design/assets/languages/atomic_qt_en.ts index 8c129439ea..07440c77bf 100644 --- a/atomic_qt_design/assets/languages/atomic_qt_en.ts +++ b/atomic_qt_design/assets/languages/atomic_qt_en.ts @@ -669,7 +669,7 @@ - Instant + - @@ -1800,43 +1800,43 @@ Trade - + Placed the order - + Failed to place the order - + Please fill the price field - + %1 balance is lower than minimum trade amount - + Not enough balance for the fees. Need at least %1 more AMT TICKER - + Please fill the volume field - + Not enough ETH for the transaction fee - + Amount is lower than minimum trade amount diff --git a/atomic_qt_design/assets/languages/atomic_qt_fr.ts b/atomic_qt_design/assets/languages/atomic_qt_fr.ts index 75b6b95344..167ca599a2 100644 --- a/atomic_qt_design/assets/languages/atomic_qt_fr.ts +++ b/atomic_qt_design/assets/languages/atomic_qt_fr.ts @@ -688,7 +688,7 @@ - Instant + - @@ -2003,43 +2003,43 @@ Impossible de placer l'ordre. - + Placed the order - + Failed to place the order - + Please fill the price field - + %1 balance is lower than minimum trade amount - + Not enough balance for the fees. Need at least %1 more AMT TICKER - + Please fill the volume field - + Not enough ETH for the transaction fee Pas assez d'ETH pour les frais de transaction - + Amount is lower than minimum trade amount diff --git a/atomic_qt_design/assets/languages/atomic_qt_tr.ts b/atomic_qt_design/assets/languages/atomic_qt_tr.ts index 3cdbf1bad8..5dc3d640c2 100644 --- a/atomic_qt_design/assets/languages/atomic_qt_tr.ts +++ b/atomic_qt_design/assets/languages/atomic_qt_tr.ts @@ -686,7 +686,7 @@ - Instant + - @@ -1998,43 +1998,43 @@ Al-Sat - + Placed the order - + Failed to place the order - + Please fill the price field - + %1 balance is lower than minimum trade amount - + Not enough balance for the fees. Need at least %1 more AMT TICKER - + Please fill the volume field - + Not enough ETH for the transaction fee - + Amount is lower than minimum trade amount diff --git a/src/atomic.dex.qt.market.pairs.cpp b/src/atomic.dex.qt.market.pairs.cpp index 82771e3a01..d29076ea20 100644 --- a/src/atomic.dex.qt.market.pairs.cpp +++ b/src/atomic.dex.qt.market.pairs.cpp @@ -25,11 +25,11 @@ namespace atomic_dex spdlog::trace("market pairs model created"); m_left_selection_box->setSourceModel(portfolio_mdl); m_left_selection_box->setDynamicSortFilter(true); - m_left_selection_box->sort_by_currency_balance(false); + m_left_selection_box->sort_by_name(true); m_right_selection_box->setSourceModel(portfolio_mdl); m_right_selection_box->setDynamicSortFilter(true); - m_right_selection_box->sort_by_currency_balance(false); + m_right_selection_box->sort_by_name(true); } market_pairs::~market_pairs() noexcept From a853ffcee0028091fa0d1929cfa9f15b7fa80096 Mon Sep 17 00:00:00 2001 From: naezith Date: Mon, 17 Aug 2020 19:19:06 +0300 Subject: [PATCH 375/515] feat(gui): combobox recovers from the list modification --- .../qml/Exchange/Trade/TickerSelector.qml | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml b/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml index 8bfcff8bd3..4dd7c86d5d 100644 --- a/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml +++ b/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml @@ -35,7 +35,25 @@ RowLayout { textRole: "display" valueRole: "ticker" - onCurrentValueChanged: setPair(left_side, currentValue) + property bool index_changed: false + onCurrentIndexChanged: { + // Save index change + index_changed = true + } + + onCurrentTextChanged: { + // Set the original coin if it's not user input/backend, because index doesn't change, we know that it's the change of the list + if(!index_changed && currentText.indexOf(ticker) === -1) + combo.currentIndex = combo.indexOfValue(ticker) + + displayText = currentText + } + + onCurrentValueChanged: { + // Reset index change + user_changed_index = false + setPair(left_side, currentValue) + } Layout.fillWidth: true } From dda53a47599564d38bdafa517c0a78839d6447ba Mon Sep 17 00:00:00 2001 From: romanszterg Date: Mon, 17 Aug 2020 18:22:19 +0200 Subject: [PATCH 376/515] feat(market_pair): if remove current selected coin set back to default --- src/atomic.dex.app.cpp | 1 + src/atomic.dex.qt.market.pairs.cpp | 12 ++++++++---- src/atomic.dex.qt.trading.page.cpp | 13 +++++++++++++ src/atomic.dex.qt.trading.page.hpp | 1 + 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/atomic.dex.app.cpp b/src/atomic.dex.app.cpp index bdcc7c19a3..599b05f198 100644 --- a/src/atomic.dex.app.cpp +++ b/src/atomic.dex.app.cpp @@ -137,6 +137,7 @@ namespace atomic_dex std::vector coins_std; system_manager_.get_system().get_portfolio()->disable_coins(coins); + system_manager_.get_system().disable_coin(coins[0]); coins_std.reserve(coins.size()); for (auto&& coin: coins) { coins_std.push_back(coin.toStdString()); } get_mm2().disable_multiple_coins(coins_std); diff --git a/src/atomic.dex.qt.market.pairs.cpp b/src/atomic.dex.qt.market.pairs.cpp index d29076ea20..448d32098f 100644 --- a/src/atomic.dex.qt.market.pairs.cpp +++ b/src/atomic.dex.qt.market.pairs.cpp @@ -66,8 +66,10 @@ namespace atomic_dex { auto current_res_left = m_left_selection_box->match(m_left_selection_box->index(0, 0), portfolio_model::PortfolioRoles::TickerRole, m_left_selected_coin); - assert(not current_res_left.empty()); - m_left_selection_box->setData(current_res_left.at(0), portfolio_model::PortfolioRoles::Excluded, false); + if (not current_res_left.empty()) + { + m_left_selection_box->setData(current_res_left.at(0), portfolio_model::PortfolioRoles::Excluded, false); + } } //! Set new one to true @@ -89,8 +91,10 @@ namespace atomic_dex { auto current_res_right = m_right_selection_box->match(m_right_selection_box->index(0, 0), portfolio_model::PortfolioRoles::TickerRole, m_right_selected_coin); - assert(not current_res_right.empty()); - m_right_selection_box->setData(current_res_right.at(0), portfolio_model::PortfolioRoles::Excluded, false); + if (not current_res_right.empty()) + { + m_right_selection_box->setData(current_res_right.at(0), portfolio_model::PortfolioRoles::Excluded, false); + } } //! Set new one to true diff --git a/src/atomic.dex.qt.trading.page.cpp b/src/atomic.dex.qt.trading.page.cpp index 82abad35a0..05c960d696 100644 --- a/src/atomic.dex.qt.trading.page.cpp +++ b/src/atomic.dex.qt.trading.page.cpp @@ -208,6 +208,19 @@ namespace atomic_dex //! Public API namespace atomic_dex { + void + trading_page::disable_coin(const QString& coin) noexcept + { + auto* market_selector_mdl = get_market_pairs_mdl(); + if (market_selector_mdl->get_left_selected_coin() == coin) { + market_selector_mdl->set_left_selected_coin("BTC"); + } + if (market_selector_mdl->get_right_selected_coin() == coin) { + market_selector_mdl->set_right_selected_coin("KMD"); + } + set_current_orderbook(market_selector_mdl->get_left_selected_coin(), market_selector_mdl->get_right_selected_coin()); + } + void trading_page::clear_models() { diff --git a/src/atomic.dex.qt.trading.page.hpp b/src/atomic.dex.qt.trading.page.hpp index 40bc896b0c..0b1a69bcb2 100644 --- a/src/atomic.dex.qt.trading.page.hpp +++ b/src/atomic.dex.qt.trading.page.hpp @@ -91,6 +91,7 @@ namespace atomic_dex void connect_signals(); void disconnect_signals(); void clear_models(); + void disable_coin(const QString& coin) noexcept;; //! Public QML API Q_INVOKABLE void set_current_orderbook(const QString& base, const QString& rel); From e2955a13b77ebab7cc9ee79626ba468e50801a29 Mon Sep 17 00:00:00 2001 From: naezith Date: Mon, 17 Aug 2020 19:28:50 +0300 Subject: [PATCH 377/515] feat(gui): code polish --- atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml b/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml index 4dd7c86d5d..02e4672c43 100644 --- a/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml +++ b/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml @@ -44,14 +44,14 @@ RowLayout { onCurrentTextChanged: { // Set the original coin if it's not user input/backend, because index doesn't change, we know that it's the change of the list if(!index_changed && currentText.indexOf(ticker) === -1) - combo.currentIndex = combo.indexOfValue(ticker) + currentIndex = indexOfValue(ticker) displayText = currentText } onCurrentValueChanged: { // Reset index change - user_changed_index = false + index_changed = false setPair(left_side, currentValue) } From b4c0f27a072338134621dae7e014ed04cbcc91fd Mon Sep 17 00:00:00 2001 From: romanszterg Date: Mon, 17 Aug 2020 18:34:40 +0200 Subject: [PATCH 378/515] feat(market_pair): if remove current selected coin set back to default --- src/atomic.dex.qt.trading.page.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/atomic.dex.qt.trading.page.cpp b/src/atomic.dex.qt.trading.page.cpp index 05c960d696..ee7b8fa2d6 100644 --- a/src/atomic.dex.qt.trading.page.cpp +++ b/src/atomic.dex.qt.trading.page.cpp @@ -214,8 +214,10 @@ namespace atomic_dex auto* market_selector_mdl = get_market_pairs_mdl(); if (market_selector_mdl->get_left_selected_coin() == coin) { market_selector_mdl->set_left_selected_coin("BTC"); + market_selector_mdl->set_right_selected_coin("KMD"); } if (market_selector_mdl->get_right_selected_coin() == coin) { + market_selector_mdl->set_left_selected_coin("BTC"); market_selector_mdl->set_right_selected_coin("KMD"); } set_current_orderbook(market_selector_mdl->get_left_selected_coin(), market_selector_mdl->get_right_selected_coin()); From f70965e835bfae2c587ddbb8aee32f9111d09125 Mon Sep 17 00:00:00 2001 From: naezith Date: Mon, 17 Aug 2020 19:55:01 +0300 Subject: [PATCH 379/515] feat(gui): loading until all coins are loaded --- atomic_qt_design/qml/Screens/InitialLoading.qml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/atomic_qt_design/qml/Screens/InitialLoading.qml b/atomic_qt_design/qml/Screens/InitialLoading.qml index ea091dac89..7602720281 100644 --- a/atomic_qt_design/qml/Screens/InitialLoading.qml +++ b/atomic_qt_design/qml/Screens/InitialLoading.qml @@ -12,11 +12,14 @@ SetupPage { // Override property var onLoaded: () => {} + readonly property string current_status: API.get().initial_loading_status + readonly property bool loaded_all_coins: API.get().portfolio_pg.portfolio_mdl.length >= API.get().enabled_coins.length + property Timer check_loading_complete: Timer { interval: 64 repeat: true onTriggered: { - if(API.get().initial_loading_status === "complete" && API.get().portfolio_pg.portfolio_mdl.length >= 2) { + if(current_status === "complete" && loaded_all_coins) { running = false onLoaded() } @@ -41,9 +44,9 @@ SetupPage { } DefaultText { - text_value: API.get().settings_pg.empty_string + ((API.get().initial_loading_status === "initializing_mm2" ? qsTr("Initializing MM2") : - API.get().initial_loading_status === "enabling_coins" ? qsTr("Enabling coins") : - API.get().initial_loading_status === "complete" && API.get().portfolio_pg.portfolio_mdl.length >= 2 ? qsTr("Complete") : qsTr("Getting ready")) + "...") + text_value: API.get().settings_pg.empty_string + ((current_status === "initializing_mm2" ? qsTr("Initializing MM2") : + current_status === "enabling_coins" ? qsTr("Enabling coins") : + current_status === "complete" && loaded_all_coins ? qsTr("Complete") : qsTr("Getting ready")) + "...") } } } From 0eff404d9762cc00ad617f44f5e81d001d9058ac Mon Sep 17 00:00:00 2001 From: romanszterg Date: Mon, 17 Aug 2020 18:58:18 +0200 Subject: [PATCH 380/515] feat(market_pair): turn into else if --- src/atomic.dex.qt.trading.page.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/atomic.dex.qt.trading.page.cpp b/src/atomic.dex.qt.trading.page.cpp index ee7b8fa2d6..e071f9fff1 100644 --- a/src/atomic.dex.qt.trading.page.cpp +++ b/src/atomic.dex.qt.trading.page.cpp @@ -212,11 +212,13 @@ namespace atomic_dex trading_page::disable_coin(const QString& coin) noexcept { auto* market_selector_mdl = get_market_pairs_mdl(); - if (market_selector_mdl->get_left_selected_coin() == coin) { + if (market_selector_mdl->get_left_selected_coin() == coin) + { market_selector_mdl->set_left_selected_coin("BTC"); market_selector_mdl->set_right_selected_coin("KMD"); } - if (market_selector_mdl->get_right_selected_coin() == coin) { + else if (market_selector_mdl->get_right_selected_coin() == coin) + { market_selector_mdl->set_left_selected_coin("BTC"); market_selector_mdl->set_right_selected_coin("KMD"); } From 5620b1ec6065e9ef9dcf493b226fcb9c35d69610 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Mon, 17 Aug 2020 19:08:31 +0200 Subject: [PATCH 381/515] update readme to set package official nim list --- ci_tools_atomic_dex/README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ci_tools_atomic_dex/README.md b/ci_tools_atomic_dex/README.md index 872d65d4af..f38619b8c7 100644 --- a/ci_tools_atomic_dex/README.md +++ b/ci_tools_atomic_dex/README.md @@ -131,6 +131,15 @@ export QT_INSTALL_CMAKE_PATH=~/Qt/5.15.0/gcc/lib/cmake export QT_ROOT=~/Qt/5.15.0 ``` +## Set Nim official packages list to our fork packages list + +``` +nimble refresh https://raw.githubusercontent.com/KomodoPlatform/nim_kmd_package_list/master/packages.json +cd ~/.nimble +mv packages_commandline.json packages_official.json +cd - +``` + ## Build AtomicDEX Pro Please clone with submodules initialization : `git clone --recurse-submodules --remote-submodules https://github.com/KomodoPlatform/atomicDEX-Pro.git` From 10d4afca8801159ebdb39f40db112e7ae0d8019b Mon Sep 17 00:00:00 2001 From: naezith Date: Mon, 17 Aug 2020 22:29:01 +0300 Subject: [PATCH 382/515] feat(gui): block swap while chart is fetching + 3s cd on set pair --- .../qml/Exchange/Trade/CandleStickChart.qml | 3 ++- .../qml/Exchange/Trade/TickerSelector.qml | 2 ++ atomic_qt_design/qml/Exchange/Trade/Trade.qml | 16 +++++++++++++++- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml b/atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml index fbaff96021..6f223f5040 100644 --- a/atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml +++ b/atomic_qt_design/qml/Exchange/Trade/CandleStickChart.qml @@ -12,6 +12,7 @@ Item { readonly property double y_margin: 0.02 readonly property bool pair_supported: cs_mapper.model.is_current_pair_supported + readonly property bool is_fetching: cs_mapper.model.is_fetching function getChartSeconds() { const idx = combo_time.currentIndex @@ -134,7 +135,7 @@ Item { ChartView { id: chart - visible: pair_supported && series.count > 0 && series.count === cs_mapper.model.series_size && !cs_mapper.model.is_fetching + visible: pair_supported && series.count > 0 && series.count === cs_mapper.model.series_size && !is_fetching height: parent.height * 0.9 width: parent.width diff --git a/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml b/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml index 02e4672c43..36faee710b 100644 --- a/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml +++ b/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml @@ -31,6 +31,8 @@ RowLayout { DefaultComboBox { id: combo + enabled: !block_everything + model: ticker_list textRole: "display" valueRole: "ticker" diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index f62dc1a22e..37edb4fe60 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -11,12 +11,20 @@ Item { property string action_result + readonly property bool block_everything: chart.is_fetching && !swap_cooldown.running + property bool sell_mode: true property string left_ticker: selector_left.ticker property string right_ticker: selector_right.ticker property string base_ticker: sell_mode ? left_ticker : right_ticker property string rel_ticker: sell_mode ? right_ticker : left_ticker + Timer { + id: swap_cooldown + repeat: false + interval: 3000 + } + // Override property var onOrderSuccess: () => {} @@ -187,6 +195,8 @@ Item { } function setPair(is_left_side, changed_ticker) { + swap_cooldown.restart() + let base = left_ticker let rel = right_ticker @@ -317,6 +327,7 @@ Item { anchors.bottomMargin: layout_margin * 2 CandleStickChart { + id: chart anchors.fill: parent } } @@ -348,7 +359,10 @@ Item { MouseArea { anchors.fill: parent - onClicked: setPair(true, right_ticker) + onClicked: { + if(!block_everything) + setPair(true, right_ticker) + } } } From 245d54af8ade27eaf10ba429f2564ee05dc45d9a Mon Sep 17 00:00:00 2001 From: naezith Date: Mon, 17 Aug 2020 22:30:39 +0300 Subject: [PATCH 383/515] feat(gui): polish block condition --- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index 37edb4fe60..29b90561b7 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -11,7 +11,7 @@ Item { property string action_result - readonly property bool block_everything: chart.is_fetching && !swap_cooldown.running + readonly property bool block_everything: chart.is_fetching || swap_cooldown.running property bool sell_mode: true property string left_ticker: selector_left.ticker From 8a079c926be77f7a6f60fe36036f707f551050fb Mon Sep 17 00:00:00 2001 From: naezith Date: Mon, 17 Aug 2020 22:37:22 +0300 Subject: [PATCH 384/515] feat(gui): lower cooldown interval --- atomic_qt_design/qml/Exchange/Trade/Trade.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/Trade.qml b/atomic_qt_design/qml/Exchange/Trade/Trade.qml index 29b90561b7..f93a4fd3b5 100644 --- a/atomic_qt_design/qml/Exchange/Trade/Trade.qml +++ b/atomic_qt_design/qml/Exchange/Trade/Trade.qml @@ -22,7 +22,7 @@ Item { Timer { id: swap_cooldown repeat: false - interval: 3000 + interval: 1000 } // Override From 338699ae954d51ee2470b534652fc63b0f10fe32 Mon Sep 17 00:00:00 2001 From: romanszterg Date: Mon, 17 Aug 2020 22:53:58 +0200 Subject: [PATCH 385/515] feat(batch): using batch request for process orderbook and fees --- src/atomic.dex.mm2.api.cpp | 22 ++++- src/atomic.dex.mm2.api.hpp | 24 ++++++ src/atomic.dex.mm2.cpp | 172 +++++++++++++++++++++++-------------- src/atomic.dex.mm2.hpp | 5 +- 4 files changed, 156 insertions(+), 67 deletions(-) diff --git a/src/atomic.dex.mm2.api.cpp b/src/atomic.dex.mm2.api.cpp index a733825976..88b9646c18 100644 --- a/src/atomic.dex.mm2.api.cpp +++ b/src/atomic.dex.mm2.api.cpp @@ -57,7 +57,7 @@ namespace mm2::api j.at("numer").get_to(cfg.numer); t_rational rat(boost::multiprecision::cpp_int(cfg.numer), boost::multiprecision::cpp_int(cfg.denom)); t_float_50 res = rat.convert_to(); - cfg.decimal = res.str(8); + cfg.decimal = res.str(8); } void @@ -1109,6 +1109,26 @@ namespace mm2::api return out; } + nlohmann::json + rpc_batch_standalone(nlohmann::json batch_array) + { + auto resp = RestClient::post(g_endpoint, "application/json", batch_array.dump()); + + spdlog::info("{} resp code: {}", __FUNCTION__, resp.code); + + nlohmann::json answer; + try + { + answer = nlohmann::json::parse(resp.body); + } + catch (const nlohmann::detail::parse_error& err) + { + spdlog::error("{}", err.what()); + answer["error"] = resp.body; + } + return answer; + } + nlohmann::json rpc_batch_electrum(std::vector requests) { diff --git a/src/atomic.dex.mm2.api.hpp b/src/atomic.dex.mm2.api.hpp index f1abb6cd9e..32aaa7a50f 100644 --- a/src/atomic.dex.mm2.api.hpp +++ b/src/atomic.dex.mm2.api.hpp @@ -26,6 +26,8 @@ namespace mm2::api { inline constexpr const char* g_endpoint = "http://127.0.0.1:7783"; + nlohmann::json rpc_batch_standalone(nlohmann::json batch_array); + std::string rpc_version(); //! max taker vol @@ -707,6 +709,28 @@ namespace mm2::api template static RpcReturnType rpc_process_answer(const RestClient::Response& resp, const std::string& rpc_command) noexcept; + template + RpcReturnType + static inline rpc_process_answer_batch(nlohmann::json& json_answer, const std::string& rpc_command) noexcept + { + RpcReturnType answer; + + try + { + from_json(json_answer, answer); + answer.rpc_result_code = 200; + } + catch (const std::exception& error) + { + spdlog::error( + "{} l{} f[{}], exception caught {} for rpc {}", __FUNCTION__, __LINE__, fs::path(__FILE__).filename().string(), error.what(), rpc_command); + answer.rpc_result_code = -1; + answer.raw_result = error.what(); + } + + return answer; + } + nlohmann::json template_request(std::string method_name) noexcept; template diff --git a/src/atomic.dex.mm2.cpp b/src/atomic.dex.mm2.cpp index aa28870f15..0bdaf9e38f 100644 --- a/src/atomic.dex.mm2.cpp +++ b/src/atomic.dex.mm2.cpp @@ -511,36 +511,119 @@ namespace atomic_dex return m_current_orderbook.at(pair); } + void + mm2::batch_process_fees_and_fetch_current_orderbook_thread(bool is_a_reset) + { + spdlog::info("batch orderbook/fees"); + if (not m_orderbook_thread_active) + { + spdlog::warn("Nothing todo, sleeping"); + return; + } + + //! Prepare fees + auto&& [orderbook_ticker_base, orderbook_ticker_rel] = m_synchronized_ticker_pair.get(); + if (orderbook_ticker_rel.empty()) return; + nlohmann::json batch = nlohmann::json::array(); + t_get_trade_fee_request req_base{.coin = orderbook_ticker_base}; + nlohmann::json current_request = ::mm2::api::template_request("get_trade_fee"); + ::mm2::api::to_json(current_request, req_base); + batch.push_back(current_request); + current_request = ::mm2::api::template_request("get_trade_fee");; + t_get_trade_fee_request req_rel{.coin = orderbook_ticker_rel}; + ::mm2::api::to_json(current_request, req_rel); + batch.push_back(current_request); + current_request = ::mm2::api::template_request("orderbook"); + t_orderbook_request req_orderbook{.base = orderbook_ticker_base, .rel = orderbook_ticker_rel}; + ::mm2::api::to_json(current_request, req_orderbook); + batch.push_back(current_request); + current_request = ::mm2::api::template_request("max_taker_vol"); + ::mm2::api::max_taker_vol_request req_base_max_taker_vol{.coin = orderbook_ticker_base}; + ::mm2::api::to_json(current_request, req_base_max_taker_vol); + batch.push_back(current_request); + current_request = ::mm2::api::template_request("max_taker_vol"); + ::mm2::api::max_taker_vol_request req_rel_max_taker_vol{.coin = orderbook_ticker_rel}; + ::mm2::api::to_json(current_request, req_rel_max_taker_vol); + batch.push_back(current_request); + auto answer = ::mm2::api::rpc_batch_standalone(batch); + + if (answer.is_array()) + { + auto trade_fee_base_answer = ::mm2::api::rpc_process_answer_batch(answer[0], "get_trade_fee"); + if (trade_fee_base_answer.rpc_result_code == 200) + { + this->m_trade_fees_registry.insert_or_assign(orderbook_ticker_base, trade_fee_base_answer); + } + + auto trade_fee_rel_answer = ::mm2::api::rpc_process_answer_batch(answer[1], "get_trade_fee"); + if (trade_fee_rel_answer.rpc_result_code == 200) + { + this->m_trade_fees_registry.insert_or_assign(orderbook_ticker_rel, trade_fee_rel_answer); + } + + auto orderbook_answer = ::mm2::api::rpc_process_answer_batch(answer[2], "orderbook"); + + if (orderbook_answer.rpc_result_code == 200) + { + m_current_orderbook.insert_or_assign(orderbook_ticker_base + "/" + orderbook_ticker_rel, orderbook_answer); + this->dispatcher_.trigger(is_a_reset); + } + + auto base_max_taker_vol_answer = ::mm2::api::rpc_process_answer_batch<::mm2::api::max_taker_vol_answer>(answer[3], "max_taker_vol"); + if (base_max_taker_vol_answer.rpc_result_code == 200) + { + this->m_synchronized_max_taker_vol->first = base_max_taker_vol_answer.result.value(); + } + + auto rel_max_taker_vol_answer = ::mm2::api::rpc_process_answer_batch<::mm2::api::max_taker_vol_answer>(answer[4], "max_taker_vol"); + if (rel_max_taker_vol_answer.rpc_result_code == 200) + { + this->m_synchronized_max_taker_vol->second = rel_max_taker_vol_answer.result.value(); + } + } + } + void mm2::process_orderbook(bool is_a_reset) { auto&& [base, rel] = m_synchronized_ticker_pair.get(); - t_orderbook_request request{.base = base, .rel = rel}; - ::mm2::api::max_taker_vol_request req_base{.coin = base}; - ::mm2::api::max_taker_vol_request req_rel{.coin = rel}; - std::array, 2> futures; - - futures[0] = spawn([&req_base, this]() { - auto answer = ::mm2::api::rpc_max_taker_vol(std::move(req_base)); - if (answer.rpc_result_code not_eq -1) + if (rel.empty()) return; + nlohmann::json batch = nlohmann::json::array(); + + nlohmann::json current_request = ::mm2::api::template_request("orderbook"); + t_orderbook_request req_orderbook{.base = base, .rel = rel}; + ::mm2::api::to_json(current_request, req_orderbook); + batch.push_back(current_request); + current_request = ::mm2::api::template_request("max_taker_vol"); + ::mm2::api::max_taker_vol_request req_base_max_taker_vol{.coin = base}; + ::mm2::api::to_json(current_request, req_base_max_taker_vol); + batch.push_back(current_request); + current_request = ::mm2::api::template_request("max_taker_vol"); + ::mm2::api::max_taker_vol_request req_rel_max_taker_vol{.coin = rel}; + ::mm2::api::to_json(current_request, req_rel_max_taker_vol); + batch.push_back(current_request); + auto answer = ::mm2::api::rpc_batch_standalone(batch); + if (answer.is_array()) + { + auto orderbook_answer = ::mm2::api::rpc_process_answer_batch(answer[0], "orderbook"); + + if (orderbook_answer.rpc_result_code == 200) { - this->m_synchronized_max_taker_vol->first = answer.result.value(); + m_current_orderbook.insert_or_assign(base + "/" + rel, orderbook_answer); + this->dispatcher_.trigger(is_a_reset); } - }); - futures[1] = spawn([&req_rel, this]() { - auto answer = ::mm2::api::rpc_max_taker_vol(std::move(req_rel)); - if (answer.rpc_result_code not_eq -1) + auto base_max_taker_vol_answer = ::mm2::api::rpc_process_answer_batch<::mm2::api::max_taker_vol_answer>(answer[1], "max_taker_vol"); + if (base_max_taker_vol_answer.rpc_result_code == 200) { - this->m_synchronized_max_taker_vol->second = answer.result.value(); + this->m_synchronized_max_taker_vol->first = base_max_taker_vol_answer.result.value(); + } + + auto rel_max_taker_vol_answer = ::mm2::api::rpc_process_answer_batch<::mm2::api::max_taker_vol_answer>(answer[2], "max_taker_vol"); + if (rel_max_taker_vol_answer.rpc_result_code == 200) + { + this->m_synchronized_max_taker_vol->second = rel_max_taker_vol_answer.result.value(); } - }); - auto answer = rpc_orderbook(std::move(request)); - if (answer.rpc_result_code not_eq -1) - { - m_current_orderbook.insert_or_assign(base + "/" + rel, answer); - for (auto&& fut: futures) { fut.wait(); } - this->dispatcher_.trigger(is_a_reset); } } @@ -771,48 +854,6 @@ namespace atomic_dex this->dispatcher_.trigger(); } - void - mm2::process_fees() - { - // loguru::set_thread_name("fees thread"); - spdlog::debug("{} l{} f[{}]", __FUNCTION__, __LINE__, fs::path(__FILE__).filename().string()); - t_coins coins = get_enabled_coins(); - std::vector> futures; - - auto&& [orderbook_ticker_base, orderbook_ticker_rel] = m_synchronized_ticker_pair.get(); - if (not m_synchronized_ticker_pair.get().second.empty()) - { - futures.reserve(2); - } - else - { - futures.reserve(1); - } - - auto rpc_fees = [this, orderbook_ticker_base = orderbook_ticker_base, orderbook_ticker_rel = orderbook_ticker_rel]() { - t_get_trade_fee_request req{.coin = orderbook_ticker_base}; - auto answer = ::mm2::api::rpc_get_trade_fee(std::move(req)); - if (answer.rpc_result_code == 200) - { - this->m_trade_fees_registry.insert_or_assign(orderbook_ticker_base, answer); - } - - if (not orderbook_ticker_rel.empty()) - { - t_get_trade_fee_request req_rel{.coin = orderbook_ticker_rel}; - auto answer_rel = ::mm2::api::rpc_get_trade_fee(std::move(req_rel)); - if (answer_rel.rpc_result_code == 200) - { - this->m_trade_fees_registry.insert_or_assign(orderbook_ticker_rel, answer_rel); - } - } - }; - - futures.emplace_back(spawn(rpc_fees)); - - for (auto&& fut: futures) { fut.get(); } - } - void mm2::process_tx(const std::string& ticker) { @@ -891,8 +932,9 @@ namespace atomic_dex if (this->m_mm2_running) { spawn([this]() { - process_fees(); - fetch_current_orderbook_thread(true); + batch_process_fees_and_fetch_current_orderbook_thread(true); + // process_fees(); + // fetch_current_orderbook_thread(true); }); } } diff --git a/src/atomic.dex.mm2.hpp b/src/atomic.dex.mm2.hpp index 5c306efb39..ac46da5190 100644 --- a/src/atomic.dex.mm2.hpp +++ b/src/atomic.dex.mm2.hpp @@ -129,11 +129,14 @@ namespace atomic_dex void process_tx(const std::string& ticker); //! Refresh the fees registry (internal) - void process_fees(); + //void process_fees(); //! Refresh the orderbook registry (internal) void process_orderbook(bool is_a_reset = false); + //! Batch process fees and fetch current_orderbook thread + void batch_process_fees_and_fetch_current_orderbook_thread(bool is_a_reset); + public: //! Constructor explicit mm2(entt::registry& registry); From b4dd61144cbe6674e8b5131b5aa020dd31afc87a Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 18 Aug 2020 00:53:55 +0300 Subject: [PATCH 386/515] feat(gui): fix combobox display text changing at list change --- .../qml/Exchange/Trade/TickerSelector.qml | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml b/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml index 36faee710b..12588423a0 100644 --- a/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml +++ b/atomic_qt_design/qml/Exchange/Trade/TickerSelector.qml @@ -38,22 +38,23 @@ RowLayout { valueRole: "ticker" property bool index_changed: false - onCurrentIndexChanged: { - // Save index change - index_changed = true - } - - onCurrentTextChanged: { - // Set the original coin if it's not user input/backend, because index doesn't change, we know that it's the change of the list - if(!index_changed && currentText.indexOf(ticker) === -1) - currentIndex = indexOfValue(ticker) - displayText = currentText + onCurrentIndexChanged: combo.index_changed = true + + onDisplayTextChanged: { + if(currentText.indexOf(ticker) === -1) { + const target_index = indexOfValue(ticker) + if(currentIndex !== target_index) { + if(!combo.index_changed) { + currentIndex = target_index + } + else combo.index_changed = false + } + } } onCurrentValueChanged: { - // Reset index change - index_changed = false + combo.index_changed = false setPair(left_side, currentValue) } From a5a0f4e84689d49e10b37a01589586f7e2f55b8e Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 18 Aug 2020 00:57:22 +0300 Subject: [PATCH 387/515] feat(gui): hide swap progress if order is matching --- atomic_qt_design/qml/Exchange/OrderModal.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomic_qt_design/qml/Exchange/OrderModal.qml b/atomic_qt_design/qml/Exchange/OrderModal.qml index 98cc23f006..a9f4f54760 100644 --- a/atomic_qt_design/qml/Exchange/OrderModal.qml +++ b/atomic_qt_design/qml/Exchange/OrderModal.qml @@ -172,7 +172,7 @@ DefaultModal { } SwapProgress { - visible: General.exists(details) && !details.is_maker + visible: General.exists(details) && details.order_status !== "matching" Layout.fillWidth: true details: root.details } From abbaa07906f2a6e669b987565187034f96db8538 Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 18 Aug 2020 01:18:08 +0300 Subject: [PATCH 388/515] feat(gui): hide horizontal line if swap progress is not visible --- atomic_qt_design/qml/Exchange/OrderModal.qml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/atomic_qt_design/qml/Exchange/OrderModal.qml b/atomic_qt_design/qml/Exchange/OrderModal.qml index a9f4f54760..889aae1410 100644 --- a/atomic_qt_design/qml/Exchange/OrderModal.qml +++ b/atomic_qt_design/qml/Exchange/OrderModal.qml @@ -165,6 +165,7 @@ DefaultModal { } HorizontalLine { + visible: swap_progress.visible Layout.fillWidth: true Layout.topMargin: 10 Layout.bottomMargin: Layout.topMargin @@ -172,6 +173,7 @@ DefaultModal { } SwapProgress { + id: swap_progress visible: General.exists(details) && details.order_status !== "matching" Layout.fillWidth: true details: root.details From f2271c1d032588627949c66855bcf0a251b59fe6 Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 18 Aug 2020 01:55:25 +0300 Subject: [PATCH 389/515] feat(gui): adaptive modal height --- atomic_qt_design/qml/Exchange/OrderModal.qml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/atomic_qt_design/qml/Exchange/OrderModal.qml b/atomic_qt_design/qml/Exchange/OrderModal.qml index 889aae1410..64784a048d 100644 --- a/atomic_qt_design/qml/Exchange/OrderModal.qml +++ b/atomic_qt_design/qml/Exchange/OrderModal.qml @@ -9,7 +9,7 @@ DefaultModal { id: root width: 900 - height: window.height - 90 + height: Math.min(header.height + inner_layout.height + footer.height + root.padding*2 + outer_layout.spacing*2, window.height - 90) property var details @@ -21,11 +21,13 @@ DefaultModal { // Inside modal ColumnLayout { + id: outer_layout width: parent.width height: parent.height anchors.horizontalCenter: parent.horizontalCenter ModalHeader { + id: header title: API.get().settings_pg.empty_string + (!details ? "" : details.is_swap ? qsTr("Swap Details") : qsTr("Order Details")) } @@ -183,6 +185,7 @@ DefaultModal { // Buttons RowLayout { + id: footer DefaultButton { text: API.get().settings_pg.empty_string + (qsTr("Close")) Layout.fillWidth: true From 0b29635c0d709d2fe5938d0fe93ad40d4b69723d Mon Sep 17 00:00:00 2001 From: naezith Date: Tue, 18 Aug 2020 14:38:19 +0300 Subject: [PATCH 390/515] feat(gui): AtomicDEX to AtomicDeFi --- ...tomicdex-logo-dark.svg => atomicdefi-logo-dark.svg} | 0 ...micdex-logo-large.svg => atomicdefi-logo-large.svg} | 0 .../images/{atomicdex-logo.svg => atomicdefi-logo.svg} | 0 atomic_qt_design/qml/Components/EulaModal.qml | 10 +++++----- atomic_qt_design/qml/Constants/API.qml | 4 ++-- atomic_qt_design/qml/Constants/Style.qml | 2 +- atomic_qt_design/qml/Dashboard/NotificationsPanel.qml | 2 +- atomic_qt_design/qml/Screens/FirstLaunch.qml | 2 +- atomic_qt_design/qml/Sidebar/Sidebar.qml | 4 ++-- atomic_qt_design/qml/main.qml | 2 +- qml.qrc | 6 +++--- 11 files changed, 16 insertions(+), 16 deletions(-) rename atomic_qt_design/assets/images/{atomicdex-logo-dark.svg => atomicdefi-logo-dark.svg} (100%) rename atomic_qt_design/assets/images/{atomicdex-logo-large.svg => atomicdefi-logo-large.svg} (100%) rename atomic_qt_design/assets/images/{atomicdex-logo.svg => atomicdefi-logo.svg} (100%) diff --git a/atomic_qt_design/assets/images/atomicdex-logo-dark.svg b/atomic_qt_design/assets/images/atomicdefi-logo-dark.svg similarity index 100% rename from atomic_qt_design/assets/images/atomicdex-logo-dark.svg rename to atomic_qt_design/assets/images/atomicdefi-logo-dark.svg diff --git a/atomic_qt_design/assets/images/atomicdex-logo-large.svg b/atomic_qt_design/assets/images/atomicdefi-logo-large.svg similarity index 100% rename from atomic_qt_design/assets/images/atomicdex-logo-large.svg rename to atomic_qt_design/assets/images/atomicdefi-logo-large.svg diff --git a/atomic_qt_design/assets/images/atomicdex-logo.svg b/atomic_qt_design/assets/images/atomicdefi-logo.svg similarity index 100% rename from atomic_qt_design/assets/images/atomicdex-logo.svg rename to atomic_qt_design/assets/images/atomicdefi-logo.svg diff --git a/atomic_qt_design/qml/Components/EulaModal.qml b/atomic_qt_design/qml/Components/EulaModal.qml index 5751bb10a0..3f9a8ee9f8 100644 --- a/atomic_qt_design/qml/Components/EulaModal.qml +++ b/atomic_qt_design/qml/Components/EulaModal.qml @@ -90,16 +90,16 @@ DefaultModal { return qsTr( "

This End-User License Agreement ('EULA') is a legal agreement between you and Komodo Platform.

-

This EULA agreement governs your acquisition and use of our AtomicDEX Pro software ('Software', 'Mobile Application', 'Application' or 'App') directly from Komodo Platform or indirectly through a Komodo Platform authorized entity, reseller or distributor (a 'Distributor').

-

Please read this EULA agreement carefully before completing the installation process and using the AtomicDEX Pro software. It provides a license to use the AtomicDEX Pro software and contains warranty information and liability disclaimers.

-

If you register for the beta program of the AtomicDEX Pro software, this EULA agreement will also govern that trial. By clicking 'accept' or installing and/or using the AtomicDEX Pro software, you are confirming your acceptance of the Software and agreeing to become bound by the terms of this EULA agreement.

+

This EULA agreement governs your acquisition and use of our AtomicDeFi Pro software ('Software', 'Mobile Application', 'Application' or 'App') directly from Komodo Platform or indirectly through a Komodo Platform authorized entity, reseller or distributor (a 'Distributor').

+

Please read this EULA agreement carefully before completing the installation process and using the AtomicDeFi Pro software. It provides a license to use the AtomicDeFi Pro software and contains warranty information and liability disclaimers.

+

If you register for the beta program of the AtomicDeFi Pro software, this EULA agreement will also govern that trial. By clicking 'accept' or installing and/or using the AtomicDeFi Pro software, you are confirming your acceptance of the Software and agreeing to become bound by the terms of this EULA agreement.

If you are entering into this EULA agreement on behalf of a company or other legal entity, you represent that you have the authority to bind such entity and its affiliates to these terms and conditions. If you do not have such authority or if you do not agree with the terms and conditions of this EULA agreement, do not install or use the Software, and you must not accept this EULA agreement.

This EULA agreement shall apply only to the Software supplied by Komodo Platform herewith regardless of whether other software is referred to or described herein. The terms also apply to any Komodo Platform updates, supplements, Internet-based services, and support services for the Software, unless other terms accompany those items on delivery. If so, those terms apply.

License Grant

-

Komodo Platform hereby grants you a personal, non-transferable, non-exclusive licence to use the AtomicDEX Pro software on your devices in accordance with the terms of this EULA agreement.

+

Komodo Platform hereby grants you a personal, non-transferable, non-exclusive licence to use the AtomicDeFi Pro software on your devices in accordance with the terms of this EULA agreement.

-

You are permitted to load the AtomicDEX Pro software (for example a PC, laptop, mobile or tablet) under your control. You are responsible for ensuring your device meets the minimum security and resource requirements of the AtomicDEX Pro software.

+

You are permitted to load the AtomicDeFi Pro software (for example a PC, laptop, mobile or tablet) under your control. You are responsible for ensuring your device meets the minimum security and resource requirements of the AtomicDeFi Pro software.

You are not permitted to:

1(w> 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