Skip to content

Introduce the BlockClock control #148

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 7 commits into from

Conversation

shaavan
Copy link
Contributor

@shaavan shaavan commented Aug 9, 2022

  • This PR introduces the Block clock control and adds it to the stub.qml to display.
  • This PR implements the syncing state of the Block Clock.
  • The implementation follows the design guide and uses this prototype as the reference.

Screenshot:

Screenshot from 2022-08-09 17-43-03

Things to note for the current implementation:

Since this is the prototype for the Block clock, I focused on the implementation part and took some liberties with the nuances, which I would like to document here.

  1. The color values for the: Remaining time text and Background color of the block clock ring didn't match the exact color values in the Theme.qml file. So I have used the closet matching Theme.color values to avoid hardcoded values and maintain consistency between light and dark mode.
  2. Since there was no "yellow" color in the Theme.qml, I have used a hardcoded value for the progress indicator.
  3. I have used the "bitcoin app" icon instead of the Black and White bitcoin icon, as this required additions to the resources and would be best done in a separate PR.
  4. I have used static dots as the peer indicator. PR Introduce PeersIndicator component #127 introduces an implementation of the peer indicator and has a largely positive review. This PR could be updated with Introduce PeersIndicator component #127's implementation when that gets merged.

@@ -312,6 +312,7 @@ QML_RES_QML = \
qml/components/StorageLocations.qml \
qml/components/StorageOptions.qml \
qml/components/StorageSettings.qml \
qml/controls/BlockClock.qml \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a component. not a control

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The next update of my PR intends to make the BlockClock.qml file a purely abstract structure and introduce a component file that uses it to paint different states of the block clock as needed. So I think moving BlockClock.qml to components now would be a wasted effort.

Should you still think I shall move the BlockClock.qml to controls, or if there is a better approach for achieving the final BlockClock state, I would love to hear that.

}
}

Canvas {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of canvas, this should be the simpler ShapePath: https://doc.qt.io/qt-6/qml-qtquick-shapes-shapepath.html

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked through using the ShapePath to paint the BlockClock. However, using this would require us to introduce a new dependency, qml-module-qtquick-shapes for building the GUI.

So I think this suggestion needs further discussion before implementing it.

A friendly ping, @hebasto

What do you think about this suggestion?

Copy link
Contributor

@promag promag Sep 8, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, from my experiments, ShapePath and related items have issues. The most annoying issue happens with small curves where tessellation yields bad curve smoothness. Another issue is that with complex drawings you end up with lots of items and bindings everywhere (especially with Repeaters), which is also not that performant.

Going forward a stack/composition of Canvas is the best option, like photoshop layers. For instance, the Canvas on the bottom could be static or updated less often than the one on the top.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, @promag, for sharing your thoughts and suggestion for using Canvas.

For instance, the Canvas on the bottom could be static or updated less often than the one on the top.

I think this would be good optimization. However, I might be putting a temporary hold on this optimization suggestion for now, as I am currently getting the Block Clock to display the block tracker, which involves some significant changes to the Canvas as well. So I shall be taking up this suggestion along with the other suggestion that shall come forth with the updated branch.

@hebasto hebasto added the UX Designers' opinions are required label Aug 12, 2022
@shaavan shaavan force-pushed the 220806-the_block_clock branch from 96311e3 to 621eae1 Compare September 27, 2022 16:22
@shaavan
Copy link
Contributor Author

shaavan commented Sep 27, 2022

Updated from 96311e3 to 055e0c0 (pr148.01 -> pr148.02)

Changes:

  • Introduces BlockClockComponent to change the displayed block clock states as needed.
  • Introduces another state of the Block clock: The block tracker.

Screenshot:
image

Note:
Currently, the time tracking is happening according to GMT and doesn't update with the locale. I am going to address this with the next update.
The main focus of this update is to get a general review of the approach I have taken for implementation.

Copy link
Member

@jarolrod jarolrod left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Branch doesn't build


const CBlockIndex* tip;
node::NodeContext* context = m_node.context();
ChainstateManager* chainman = context->chainman.get();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is too low level of an object to be handling here when we have interfaces::chain

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me take a look into replacing this low-level object handling with interfaces::chain

double verificationProgress() const { return m_verification_progress; }
void setVerificationProgress(double new_progress);
QVariantList blockTimeList() const { return m_block_time_list; }
bool setBlockTimeList(int new_block_time);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why should the nodemodel, a proxy class for our internal node, keep something like a blocklist?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Considering your previous suggestion about using the interfaces::chain, I think I can create a separate .cpp file handling chain-related parameters such as blockTimeList

import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15

Item {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the implementation of the block clock, and the file residing at src/qml/components/BlockClockComponent.qml is just a controller for this. A better architecture is to have a controller that loads the different states the block clock can be in.

You'd be able to split up this file, as it is very long, between a simple circular progress bar that shows the verification progress while in IBD, then another dial like progress bar for the blocks. Then load these into the controller.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me try rephrasing your suggestion to ensure I understood it correctly.
You suggest I create a separate component file for each block clock state, create a controller file in qml/control, and switch to loading different block clock component files based on the requirement.

Have I understood it correctly?

sourceSize.height: 30
Layout.bottomMargin: 15
}
Text {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't this recreating our header component?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it is. Thanks for pointing that out. I shall fix this with the next update of the PR.

return true;
}

void NodeModel::setBlockTimeListInitial(const CBlockIndex* pblockindex)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this is definitely too low level for us to be passing around here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me experiment with interfaces::chain and devise an approach that avoids low-level object handling.

@shaavan shaavan force-pushed the 220806-the_block_clock branch from 621eae1 to 1f134fd Compare September 28, 2022 13:50
@shaavan
Copy link
Contributor Author

shaavan commented Sep 28, 2022

Updated from 621eae1 to 1f134fd (pr148.02 -> pr148.03, diff)
Addressed @jarolrod comment

Update:

  • Made changes to fix the problem of the branch not building. Thanks, @jarolrod, for bringing that to notice and helping figure out the root of the problem.

@shaavan shaavan force-pushed the 220806-the_block_clock branch from 1f134fd to 23f8a83 Compare November 28, 2022 17:24
@shaavan
Copy link
Contributor Author

shaavan commented Nov 28, 2022

Updated from 23f8a83 to 621eae1 (pr148.03 -> pr148.04)

Changes:

  • Introduced a new chainmodel class to use the interfaces::chain and directly use the chain info without going too low level in the code.
  • The new Block Clock displays the timezone-dependent block time data.
  • Added property to Header.qml so it can be used directly in the BlockClock.qml file.

Here is the demo of the latest iteration of the block clock:

Block_Clock_demo.mov

@shaavan shaavan force-pushed the 220806-the_block_clock branch from 23f8a83 to 2a5e998 Compare December 12, 2022 14:37
@shaavan
Copy link
Contributor Author

shaavan commented Dec 12, 2022

Updated from 621eae1 to 2a5e998 (pr148.04 -> pr148.05)

Changes:

  1. Rebased over main.
  2. Added the Connecting and Paused state for the block clock.
  3. Integrated the first three commits of Introduce PeersIndicator component #127. This allows the PeerIndicator dots to be animated and correctly show the peer connection state.

Demo:

Screen.Recording.2022-12-12.at.7.21.57.PM.mov

@GBKS
Copy link
Contributor

GBKS commented Dec 13, 2022

Thanks for the updates. It looks like the artifacts are not building due a lint issue (the Android build is only 22 bytes). Could you please address this? I'd love to get hands-on with this update.

Copy link
Member

@hebasto hebasto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To fix the lint task, suggesting the patch as follows:

diff --git a/src/qml/chainmodel.h b/src/qml/chainmodel.h
index 9ab25f35c..2943c9c16 100644
--- a/src/qml/chainmodel.h
+++ b/src/qml/chainmodel.h
@@ -2,8 +2,8 @@
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
-#ifndef BITCOIN_QML_CHAIN_MODEL_H
-#define BITCOIN_QML_CHAIN_MODEL_H
+#ifndef BITCOIN_QML_CHAINMODEL_H
+#define BITCOIN_QML_CHAINMODEL_H
 
 #include <interfaces/chain.h>
 
@@ -47,4 +47,4 @@ private:
     interfaces::Chain& m_chain;
 };
 
-#endif // BITCOIN_QML_CHAIN_MODEL_H
\ No newline at end of file
+#endif // BITCOIN_QML_CHAINMODEL_H

@shaavan
Copy link
Contributor Author

shaavan commented Dec 15, 2022

Updated from 2a5e998 to 0f5461e (pr148.05 -> pr148.06)

Addressed @hebasto @jarolrod @GBKS comments.

Changes:

  1. Switch the Bitcoin app icon for the Bitcoin-circle icon.
  2. Fixed QObject::moveToThread: Cannot move objects with a parent warning.
  3. Correction Font size and margins according to design docs.
  4. Removed .vscode/settings.json file.
  5. Applied the patch suggested by @hebasto to fix the lint warning.

Screenshots:

pr148.05 pr148.06
Screenshot 2022-12-15 at 11 51 04 PM Screenshot 2022-12-15 at 11 48 44 PM
Screenshot 2022-12-15 at 11 52 02 PM Screenshot 2022-12-15 at 11 49 19 PM
Screenshot 2022-12-15 at 11 51 32 PM Screenshot 2022-12-15 at 11 49 51 PM
Screenshot 2022-12-15 at 11 51 30 PM Screenshot 2022-12-15 at 11 49 43 PM

@shaavan shaavan force-pushed the 220806-the_block_clock branch from 0f5461e to 0fbe6c8 Compare December 15, 2022 19:20
@shaavan
Copy link
Contributor Author

shaavan commented Dec 15, 2022

Updated from 0f5461e to 0fbe6c8 (pr148.06 -> pr148.07)

  • Rebased the branch over the main.

@shaavan shaavan force-pushed the 220806-the_block_clock branch from 0fbe6c8 to 29f019e Compare December 15, 2022 19:26
@shaavan
Copy link
Contributor Author

shaavan commented Dec 15, 2022

Updated from 0fbe6c8 to 29f019e

  • Fixed the trailing whitespace lint failure.

@shaavan
Copy link
Contributor Author

shaavan commented Dec 18, 2022

Updated from 29f019e to 8173bf6 (pr148.08 -> pr148.09)

  • Moved the simplified block_clock changes from Simplified version of Block Clock #212 to this PR to preserve the comment history for the block_clock and prevent splitting of discussion in two separate PRs.

Differences as explained in #212 Description:

  1. The PeersIndicator has been replaced with plain rectangles to keep the UI intact.
  2. The conns property representing if the number of connections is greater than 0, has been set to always positive. With this > change, the "connecting" page, though implemented, becomes inaccessible through the UI.

Copy link
Collaborator

@johnny9 johnny9 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Views look nice and render correctly. Tested pause/unpause as well as a full sync on signet at got the following results.

Screenshot_2022-12-16_22-18-31 Screenshot_2022-12-16_22-19-02 Screenshot_2022-12-16_22-25-01 Screenshot_2022-12-16_22-26-42 Screenshot_2022-12-16_22-28-51

A few QML errors when running that need to be resolved before merging. I've left comments for those errors at the corresponding line numbers.

tail -f debug.log | grep GUI to watch for issues when running bitcoin-qt.

@shaavan shaavan force-pushed the 220806-the_block_clock branch from 8173bf6 to bcbc80b Compare December 18, 2022 15:44
@shaavan
Copy link
Contributor Author

shaavan commented Dec 18, 2022

Updated from 8173bf6 to bcbc80b (pr148.09 -> pr148.10)

Addressed @johnny9 comments.

Changes:

  1. Fixed Type Errors as pointed out in this comment.
  2. Added space before and after operator in BlockClock.qml
  3. Added a new line at the end of the file in chainmodel.cpp and chainmodel.h.
  4. Removed the redundant ColumnLayout in Noderunner.qml.

@hebasto
Copy link
Member

hebasto commented Dec 19, 2022

The CI lint task error:

fatal: Invalid revision range fd4e57f63654e2d8e7d0de0aafc335715a53a5cc..c4e1ce262ffb5e6956a7b912f2dcf7560823682e

looks a bit weird as I failed to find a branch the c4e1ce2 commit belongs to.

I hope rebasing will help.

@shaavan And please make sure your local branch does not contain any merge commits.

- This method would allow to get the blocktime value of the block at
  the given height.
@shaavan
Copy link
Contributor Author

shaavan commented Dec 19, 2022

Updated from bcbc80b to 68fa33b (pr148.10 -> pr148.11)

  • Rebased PR over current main.

@shaavan shaavan force-pushed the 220806-the_block_clock branch from bcbc80b to 68fa33b Compare December 19, 2022 13:01
Copy link
Collaborator

@johnny9 johnny9 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QML error when going into the paused state still exists. Other issues are resolved.

@shaavan
Copy link
Contributor Author

shaavan commented Dec 20, 2022

Updated from 68fa33b to 20b4ed5 (pr148.11 -> pr148.12, diff)

Addressed @johnny9 comment.

  • Fixed TypeError: Value is undefined and could not be converted to an object error.

  • Also addressed one formatting issue, present in displaying Block Counter.

Explaination:

For example, for the block count of 122010, difference:

pr148.11 pr148.12
Screenshot 2022-12-20 at 5 54 00 PM Screenshot 2022-12-20 at 6 16 46 PM

@shaavan shaavan force-pushed the 220806-the_block_clock branch 2 times, most recently from 20b4ed5 to abb0bef Compare December 20, 2022 13:04
@shaavan
Copy link
Contributor Author

shaavan commented Dec 20, 2022

Updated from 20b4ed5 to abb0bef (pr148.12 -> pr148.13, diff)

  • Modified timeRatioList so that blockClock start displaying from the "0" point.

Screenshot:

pr148.12 pr148.13
Screenshot 2022-12-20 at 6 28 41 PM Screenshot 2022-12-20 at 6 27 57 PM

Copy link
Collaborator

@johnny9 johnny9 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good work on this Shashwat. All of the QML errors appear to be resolved now. Views render as expected

int64_t getBlockTime(int height) override
{
LOCK(::cs_main);
return Assert(chainman().ActiveChain()[height])->GetBlockTime();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fec6a0e

In Chain interface, probably better to use a type-safe CBlockIndex::Time()

gui-qml/src/chain.h

Lines 279 to 282 in fd4e57f

NodeSeconds Time() const
{
return NodeSeconds{std::chrono::seconds{nTime}};
}

Anyway, it will take a broader discussion when it will about to merge into the main repo.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, let me look through it.

it will take a broader discussion when it will about to merge into the main repo.

Let me include that, along with other future suggestions for this file.

Comment on lines 15 to 21
timer = new QTimer();
connect(timer, &QTimer::timeout, this, &ChainModel::setCurrentTimeRatio);
timer->start(1000);

QThread* timer_thread = new QThread;
timer->moveToThread(timer_thread);
timer_thread->start();
Copy link
Member

@hebasto hebasto Dec 20, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a287f9e

Sorry, if I missed any previous discussion about that, but why is calling of ChainModel::setCurrentTimeRatio implemented like that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The currentTimeRatio represents the ratio of 12 hours that has been passed.
So, for example, at 4 am or pm, the currenTimeRatio would be 0.3.

We need to update this information in the blockClock each second so that the blockClock always shows the correct blockTime.

So that's why I created a separate 1-sec timer thread to call this function each second and update the currentTimeRatio.

- This file allowing using of Chain interfaces to get information about
  the blockchain.
- This class declares and defines the function that will be used in
  for the Block Clock.
1. Added a new Q_PROPERTY to track the remaining time till the IBD
   completioni.
2. Added two signals to later connect to the chainmodel class function.
3. Added new member variable, m_pause, which will keep track of if the
   block clock is in paused state or not, and will accordingly
disconnect or reconnect the user to network.
- Also made appropriate connections with the nodemodel signals
- This property will later be used for the BlockClock.qml file
- The BlockClock.qml files provides the control for BlockClock and
  determines how the elements would be displayed.
- The BlockClockComponent.qml file uses the aforementioned control to
  display the value, and determines what will be displayed.
@shaavan shaavan force-pushed the 220806-the_block_clock branch from abb0bef to 67d12a6 Compare December 21, 2022 13:45
@shaavan
Copy link
Contributor Author

shaavan commented Dec 21, 2022

Updated from abb0bef to 67d12a6 (pr148.13 -> pr148.14, diff)

Addressed @hebasto comments.

Changes:

  • Changed 1-sec QTimer from a global private member variable to a local variable.
  • Changed names of variables mentioned in this comment from camel-style naming to snake-style naming. For full diff, check diff.
  • Added descriptive comment for m_time_ratio_list, and the values it stores.

@hebasto
Copy link
Member

hebasto commented Jan 25, 2023

Closing in favor of #220.

@hebasto hebasto closed this Jan 25, 2023
hebasto added a commit that referenced this pull request Jan 29, 2023
6701ad2 qml: introduce the BlockClock (johnny9)
60bd8cb qml: introduce ChainModel (johnny9)
eb945ac qml: add sync time related properties to NodeModel (johnny9)
8db7f0f qml: add additional properties in Header (johnny9)
094a2c4 qml: add ability to pause NodeModel (johnny9)
1fce853 Add getBlockTime interface method in src/interfaces/chain.h (shaavan)

Pull request description:

  This is a continuation of #148. The goal of this PR is to get the working features from #148 merged in using a QQuickPainterItem implementation of the dial instead of the javascript canvas.  Connection state as well as the animating icon will be implemented in a later PR. Refactoring and clean up from the removal of the Canvas code still remains.

  [![Windows](https://img.shields.io/badge/OS-Windows-green)](https://api.cirrus-ci.com/v1/artifact/github/bitcoin-core/gui-qml/win64/insecure_win_gui.zip?branch=pull/220)
  [![Intel macOS](https://img.shields.io/badge/OS-Intel%20macOS-green)](https://api.cirrus-ci.com/v1/artifact/github/bitcoin-core/gui-qml/macos/insecure_mac_gui.zip?branch=pull/220)
  [![Apple Silicon macOS](https://img.shields.io/badge/OS-Apple%20Silicon%20macOS-green)](https://api.cirrus-ci.com/v1/artifact/github/bitcoin-core/gui-qml/macos_arm64/insecure_mac_arm64_gui.zip?branch=pull/220)
  [![ARM64 Android](https://img.shields.io/badge/OS-Android-green)](https://api.cirrus-ci.com/v1/artifact/github/bitcoin-core/gui-qml/android/insecure_android_apk.zip?branch=pull/220)

ACKs for top commit:
  jarolrod:
    ACK 6701ad2

Tree-SHA512: 43b99d1fd69b67b285e91e05d3864c7044917cd6feae97b4c226f3a7b499ca24f6e786575dbc700461b1f6c58c0273746e4ea5834c554fa4dc916868199698df
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs rebase UX Designers' opinions are required
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants