Skip to content

Commit 2e5a0d8

Browse files
johnny9shaavan
andcommitted
qml: introduce the BlockClock control
Implements a few of the BlockClock dial states. Sync progress while downloading, rendering blocks after sync, and pausing/unpausing the node. An additional Model is added, ChainModel, to provide the dial block information. Changes to NodeModel are also made to support the pausing/unpausing Dial feature. Co-authored-by: shaavan <[email protected]>
1 parent 1fce853 commit 2e5a0d8

15 files changed

+638
-25
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ share/qt/Info.plist
4646

4747
src/qt/*.moc
4848
src/qt/moc_*.cpp
49+
src/qml/components/moc_*.cpp
4950
src/qt/forms/ui_*.h
5051

5152
src/qt/test/moc*.cpp

src/Makefile.qt.include

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ QT_FORMS_UI = \
3535
qt/forms/transactiondescdialog.ui
3636

3737
QT_MOC_CPP = \
38+
qml/components/moc_blockclockdial.cpp \
3839
qml/moc_appmode.cpp \
40+
qml/moc_chainmodel.cpp \
3941
qml/moc_nodemodel.cpp \
4042
qml/moc_options_model.cpp \
4143
qt/moc_addressbookpage.cpp \
@@ -111,6 +113,8 @@ QT_QRC_LOCALE = qt/bitcoin_locale.qrc
111113
BITCOIN_QT_H = \
112114
qml/appmode.h \
113115
qml/bitcoin.h \
116+
qml/chainmodel.h \
117+
qml/components/blockclockdial.h \
114118
qml/imageprovider.h \
115119
qml/nodemodel.h \
116120
qml/options_model.h \
@@ -291,6 +295,8 @@ BITCOIN_QT_WALLET_CPP = \
291295

292296
BITCOIN_QML_BASE_CPP = \
293297
qml/bitcoin.cpp \
298+
qml/chainmodel.cpp \
299+
qml/components/blockclockdial.cpp \
294300
qml/imageprovider.cpp \
295301
qml/nodemodel.cpp \
296302
qml/options_model.cpp \
@@ -329,6 +335,7 @@ QML_RES_QML = \
329335
qml/components/StorageLocations.qml \
330336
qml/components/StorageOptions.qml \
331337
qml/components/StorageSettings.qml \
338+
qml/controls/BlockClock.qml \
332339
qml/controls/ContinueButton.qml \
333340
qml/controls/ExternalLink.qml \
334341
qml/controls/Header.qml \

src/qml/bitcoin.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,15 @@
66

77
#include <chainparams.h>
88
#include <init.h>
9+
#include <interfaces/chain.h>
910
#include <interfaces/init.h>
1011
#include <interfaces/node.h>
1112
#include <logging.h>
1213
#include <node/interface_ui.h>
1314
#include <noui.h>
1415
#include <qml/appmode.h>
16+
#include <qml/chainmodel.h>
17+
#include <qml/components/blockclockdial.h>
1518
#include <qml/imageprovider.h>
1619
#include <qml/nodemodel.h>
1720
#include <qml/options_model.h>
@@ -155,6 +158,7 @@ int QmlGuiMain(int argc, char* argv[])
155158
GUIUtil::LogQtInfo();
156159

157160
std::unique_ptr<interfaces::Node> node = init->makeNode();
161+
std::unique_ptr<interfaces::Chain> chain = init->makeChain();
158162
if (!node->baseInitialize()) {
159163
// A dialog with detailed error will have been shown by InitError().
160164
return EXIT_FAILURE;
@@ -170,6 +174,11 @@ int QmlGuiMain(int argc, char* argv[])
170174
QObject::connect(&init_executor, &InitExecutor::shutdownResult, qGuiApp, &QGuiApplication::quit, Qt::QueuedConnection);
171175
// QObject::connect(&init_executor, &InitExecutor::runawayException, &node_model, &NodeModel::handleRunawayException);
172176

177+
ChainModel chain_model{*chain};
178+
179+
QObject::connect(&node_model, &NodeModel::setTimeRatioList, &chain_model, &ChainModel::setTimeRatioList);
180+
QObject::connect(&node_model, &NodeModel::setTimeRatioListInitial, &chain_model, &ChainModel::setTimeRatioListInitial);
181+
173182
qGuiApp->setQuitOnLastWindowClosed(false);
174183
QObject::connect(qGuiApp, &QGuiApplication::lastWindowClosed, [&] {
175184
node->startShutdown();
@@ -185,6 +194,7 @@ int QmlGuiMain(int argc, char* argv[])
185194
engine.addImageProvider(QStringLiteral("images"), new ImageProvider{network_style.data()});
186195

187196
engine.rootContext()->setContextProperty("nodeModel", &node_model);
197+
engine.rootContext()->setContextProperty("chainModel", &chain_model);
188198

189199
OptionsQmlModel options_model{*node};
190200
engine.rootContext()->setContextProperty("optionsModel", &options_model);
@@ -196,6 +206,7 @@ int QmlGuiMain(int argc, char* argv[])
196206
#endif // __ANDROID__
197207

198208
qmlRegisterSingletonInstance<AppMode>("org.bitcoincore.qt", 1, 0, "AppMode", &app_mode);
209+
qmlRegisterType<BlockClockDial>("org.bitcoincore.qt", 1, 0, "BlockClockDial");
199210

200211
engine.load(QUrl(QStringLiteral("qrc:///qml/pages/main.qml")));
201212
if (engine.rootObjects().isEmpty()) {

src/qml/bitcoin_qml.qrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
<file>components/StorageLocations.qml</file>
99
<file>components/StorageOptions.qml</file>
1010
<file>components/StorageSettings.qml</file>
11+
<file>controls/BlockClock.qml</file>
1112
<file>controls/ContinueButton.qml</file>
1213
<file>controls/ExternalLink.qml</file>
1314
<file>controls/Header.qml</file>

src/qml/chainmodel.cpp

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// Copyright (c) 2022 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#include <qml/chainmodel.h>
6+
7+
#include <QDateTime>
8+
#include <QThread>
9+
#include <QTime>
10+
#include <interfaces/chain.h>
11+
12+
ChainModel::ChainModel(interfaces::Chain& chain)
13+
: m_chain{chain}
14+
{
15+
QTimer* timer = new QTimer();
16+
connect(timer, &QTimer::timeout, this, &ChainModel::setCurrentTimeRatio);
17+
timer->start(1000);
18+
19+
QThread* timer_thread = new QThread;
20+
timer->moveToThread(timer_thread);
21+
timer_thread->start();
22+
}
23+
24+
void ChainModel::setTimeRatioList(int new_time)
25+
{
26+
int time_at_meridian = timestampAtMeridian();
27+
28+
if (new_time < time_at_meridian) {
29+
return;
30+
}
31+
32+
m_time_ratio_list.push_back(double(new_time - time_at_meridian) / SECS_IN_12_HOURS);
33+
34+
Q_EMIT timeRatioListChanged();
35+
}
36+
37+
int ChainModel::timestampAtMeridian()
38+
{
39+
int secs_since_meridian = (QTime::currentTime().msecsSinceStartOfDay() / 1000) % SECS_IN_12_HOURS;
40+
int current_timestamp = QDateTime::currentSecsSinceEpoch();
41+
42+
return current_timestamp - secs_since_meridian;
43+
}
44+
45+
void ChainModel::setTimeRatioListInitial()
46+
{
47+
int time_at_meridian = timestampAtMeridian();
48+
int first_block_height;
49+
int active_chain_height = m_chain.getHeight().value();
50+
bool success = m_chain.findFirstBlockWithTimeAndHeight(/*min_time=*/time_at_meridian, /*min_height=*/0, interfaces::FoundBlock().height(first_block_height));
51+
52+
if (!success) {
53+
return;
54+
}
55+
56+
m_time_ratio_list.clear();
57+
/* m_time_ratio_list[0] = current_time_ratio
58+
* m_time_ratio_list[1] = 0
59+
* These two positions remain fixed for these
60+
* values in m_time_ratio_list */
61+
m_time_ratio_list.push_back(double(QDateTime::currentSecsSinceEpoch() - time_at_meridian) / SECS_IN_12_HOURS);
62+
m_time_ratio_list.push_back(0);
63+
64+
for (int height = first_block_height; height < active_chain_height + 1; height++) {
65+
m_time_ratio_list.push_back(double(m_chain.getBlockTime(height) - time_at_meridian) / SECS_IN_12_HOURS);
66+
}
67+
68+
Q_EMIT timeRatioListChanged();
69+
}
70+
71+
void ChainModel::setCurrentTimeRatio()
72+
{
73+
int secs_since_meridian = (QTime::currentTime().msecsSinceStartOfDay() / 1000) % SECS_IN_12_HOURS;
74+
double current_time_ratio = double(secs_since_meridian) / SECS_IN_12_HOURS;
75+
76+
if (current_time_ratio < m_time_ratio_list[0].toDouble()) { // That means time has crossed a meridian
77+
m_time_ratio_list.clear();
78+
}
79+
80+
if (m_time_ratio_list.isEmpty()) {
81+
m_time_ratio_list.push_back(current_time_ratio);
82+
m_time_ratio_list.push_back(0);
83+
} else {
84+
m_time_ratio_list[0] = current_time_ratio;
85+
}
86+
87+
Q_EMIT timeRatioListChanged();
88+
}

src/qml/chainmodel.h

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright (c) 2022 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#ifndef BITCOIN_QML_CHAINMODEL_H
6+
#define BITCOIN_QML_CHAINMODEL_H
7+
8+
#include <interfaces/chain.h>
9+
10+
#include <QObject>
11+
#include <QTimer>
12+
#include <QVariant>
13+
14+
namespace interfaces {
15+
class FoundBlock;
16+
class Chain;
17+
} // namespace interfaces
18+
19+
static const int SECS_IN_12_HOURS = 43200;
20+
21+
class ChainModel : public QObject
22+
{
23+
Q_OBJECT
24+
Q_PROPERTY(QVariantList timeRatioList READ timeRatioList NOTIFY timeRatioListChanged)
25+
26+
public:
27+
explicit ChainModel(interfaces::Chain& chain);
28+
29+
QVariantList timeRatioList() const { return m_time_ratio_list; };
30+
31+
int timestampAtMeridian();
32+
33+
void setCurrentTimeRatio();
34+
35+
public Q_SLOTS:
36+
void setTimeRatioList(int new_time);
37+
void setTimeRatioListInitial();
38+
39+
Q_SIGNALS:
40+
void timeRatioListChanged();
41+
42+
private:
43+
/* time_ratio: Ratio between the time at which an event
44+
* happened and 12 hours. So, for example, if a block is
45+
* found at 4 am or pm, the time_ratio would be 0.3.
46+
* The m_time_ratio_list stores the time ratio value for
47+
* the current_time and the time at which the blocks in
48+
* the last 12 hours were mined. */
49+
QVariantList m_time_ratio_list{0.0};
50+
51+
interfaces::Chain& m_chain;
52+
};
53+
54+
#endif // BITCOIN_QML_CHAINMODEL_H

0 commit comments

Comments
 (0)