Skip to content

Commit 9fad779

Browse files
committed
qml: Introduce UI Flow for Loading Snapshot
- This introduce the UI flow to load a AssumeUTXO snapshot - It modifies the connection settings - Adds a SnapshotSettings file, Icon, and modified progress bar. - Also it adds error page on snapshotloading failure
1 parent 2e7bef0 commit 9fad779

18 files changed

+454
-1
lines changed

src/Makefile.qt.include

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,12 +360,16 @@ QML_RES_ICONS = \
360360
qml/res/icons/check.png \
361361
qml/res/icons/copy.png \
362362
qml/res/icons/coinbase.png \
363+
qml/res/icons/circle-file.png \
364+
qml/res/icons/circle-green-check.png \
365+
qml/res/icons/circle-red-cross.png \
363366
qml/res/icons/cross.png \
364367
qml/res/icons/error.png \
365368
qml/res/icons/export.png \
366369
qml/res/icons/flip-vertical.png \
367370
qml/res/icons/gear.png \
368371
qml/res/icons/gear-outline.png \
372+
qml/res/icons/green-check.png \
369373
qml/res/icons/hidden.png \
370374
qml/res/icons/info.png \
371375
qml/res/icons/minus.png \
@@ -400,6 +404,7 @@ QML_RES_QML = \
400404
qml/components/NetworkIndicator.qml \
401405
qml/components/ProxySettings.qml \
402406
qml/components/Separator.qml \
407+
qml/components/SnapshotSettings.qml \
403408
qml/components/StorageLocations.qml \
404409
qml/components/StorageOptions.qml \
405410
qml/components/StorageSettings.qml \
@@ -457,6 +462,7 @@ QML_RES_QML = \
457462
qml/pages/settings/SettingsDeveloper.qml \
458463
qml/pages/settings/SettingsDisplay.qml \
459464
qml/pages/settings/SettingsProxy.qml \
465+
qml/pages/settings/SettingsSnapshot.qml \
460466
qml/pages/settings/SettingsStorage.qml \
461467
qml/pages/settings/SettingsTheme.qml \
462468
qml/pages/wallet/Activity.qml \

src/qml/bitcoin_qml.qrc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
<file>components/ProxySettings.qml</file>
1616
<file>components/StorageLocations.qml</file>
1717
<file>components/Separator.qml</file>
18+
<file>components/SnapshotSettings.qml</file>
1819
<file>components/StorageOptions.qml</file>
1920
<file>components/StorageSettings.qml</file>
2021
<file>components/ThemeSettings.qml</file>
@@ -26,6 +27,7 @@
2627
<file>controls/CoreTextField.qml</file>
2728
<file>controls/ExternalLink.qml</file>
2829
<file>controls/FocusBorder.qml</file>
30+
<file>controls/GreenCheckIcon.qml</file>
2931
<file>controls/Header.qml</file>
3032
<file>controls/Icon.qml</file>
3133
<file>controls/InformationPage.qml</file>
@@ -70,6 +72,7 @@
7072
<file>pages/settings/SettingsDeveloper.qml</file>
7173
<file>pages/settings/SettingsDisplay.qml</file>
7274
<file>pages/settings/SettingsProxy.qml</file>
75+
<file>pages/settings/SettingsSnapshot.qml</file>
7376
<file>pages/settings/SettingsStorage.qml</file>
7477
<file>pages/settings/SettingsTheme.qml</file>
7578
<file>pages/wallet/Activity.qml</file>
@@ -103,12 +106,16 @@
103106
<file alias="check">res/icons/check.png</file>
104107
<file alias="copy">res/icons/copy.png</file>
105108
<file alias="coinbase">res/icons/coinbase.png</file>
109+
<file alias="circle-file">res/icons/circle-file.png</file>
110+
<file alias="circle-green-check">res/icons/circle-green-check.png</file>
111+
<file alias="circle-red-cross">res/icons/circle-red-cross.png</file>
106112
<file alias="cross">res/icons/cross.png</file>
107113
<file alias="error">res/icons/error.png</file>
108114
<file alias="export">res/icons/export.png</file>
109115
<file alias="flip-vertical">res/icons/flip-vertical.png</file>
110116
<file alias="gear">res/icons/gear.png</file>
111117
<file alias="gear-outline">res/icons/gear-outline.png</file>
118+
<file alias="green-check">res/icons/green-check.png</file>
112119
<file alias="hidden">res/icons/hidden.png</file>
113120
<file alias="info">res/icons/info.png</file>
114121
<file alias="minus">res/icons/minus.png</file>

src/qml/components/ConnectionSettings.qml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,38 @@ import "../controls"
1010
ColumnLayout {
1111
id: root
1212
signal next
13+
signal gotoSnapshot
14+
property bool onboarding: false
15+
property bool snapshotImportCompleted: onboarding ? false : chainModel.isSnapshotActive
16+
property bool isIBDCompleted: nodeModel.isIBDCompleted
1317
spacing: 4
18+
Setting {
19+
id: gotoSnapshot
20+
visible: !root.onboarding && !snapshotImportCompleted && !root.isIBDCompleted
21+
Layout.fillWidth: true
22+
header: qsTr("Load snapshot")
23+
description: qsTr("Instant use with background sync")
24+
actionItem: Item {
25+
width: 26
26+
height: 26
27+
CaretRightIcon {
28+
anchors.centerIn: parent
29+
visible: !snapshotImportCompleted
30+
color: gotoSnapshot.stateColor
31+
}
32+
GreenCheckIcon {
33+
anchors.centerIn: parent
34+
visible: snapshotImportCompleted
35+
color: Theme.color.transparent
36+
size: 30
37+
}
38+
}
39+
onClicked: root.gotoSnapshot()
40+
}
41+
Separator {
42+
visible: !root.onboarding && !snapshotImportCompleted
43+
Layout.fillWidth: true
44+
}
1445
Setting {
1546
Layout.fillWidth: true
1647
header: qsTr("Enable listening")
Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
// Copyright (c) 2023-present 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+
import QtQuick 2.15
6+
import QtQuick.Controls 2.15
7+
import QtQuick.Layouts 1.15
8+
import QtQuick.Dialogs 1.3
9+
10+
import "../controls"
11+
12+
ColumnLayout {
13+
id: columnLayout
14+
signal back
15+
property bool snapshotLoading: nodeModel.snapshotLoading
16+
property bool snapshotLoaded: nodeModel.isSnapshotLoaded
17+
property bool snapshotImportCompleted: onboarding ? false : chainModel.isSnapshotActive
18+
property bool onboarding: false
19+
property bool snapshotVerified: onboarding ? false : chainModel.isSnapshotActive
20+
property string snapshotFileName: ""
21+
property var snapshotInfo: (snapshotVerified || snapshotLoaded) ? chainModel.getSnapshotInfo() : ({})
22+
property string selectedFile: ""
23+
property bool headersSynced: nodeModel.headersSynced
24+
property bool snapshotError: false
25+
26+
width: Math.min(parent.width, 450)
27+
anchors.horizontalCenter: parent.horizontalCenter
28+
29+
StackLayout {
30+
id: settingsStack
31+
currentIndex: onboarding ? 0 : snapshotLoaded ? 2 : snapshotVerified ? 2 : snapshotLoading ? 1 : snapshotError ? 3 : 0
32+
33+
ColumnLayout {
34+
Layout.alignment: Qt.AlignHCenter
35+
Layout.preferredWidth: Math.min(parent.width, 450)
36+
37+
Image {
38+
Layout.alignment: Qt.AlignCenter
39+
source: "image://images/circle-file"
40+
41+
sourceSize.width: 200
42+
sourceSize.height: 200
43+
}
44+
45+
Header {
46+
Layout.fillWidth: true
47+
Layout.topMargin: 20
48+
headerBold: true
49+
header: qsTr("Load snapshot")
50+
descriptionBold: false
51+
descriptionColor: Theme.color.neutral6
52+
descriptionSize: 17
53+
descriptionLineHeight: 1.1
54+
description: qsTr("You can start using the application more quickly by loading a recent transaction snapshot." +
55+
" It will be automatically verified in the background.")
56+
}
57+
58+
CoreText {
59+
Layout.fillWidth: true
60+
Layout.topMargin: 20
61+
color: Theme.color.neutral6
62+
font.pixelSize: 17
63+
visible: !headersSynced
64+
text: !headersSynced
65+
? qsTr("Please wait for headers to sync before loading a snapshot.")
66+
: qsTr("")
67+
wrap: true
68+
wrapMode: Text.WordWrap
69+
}
70+
71+
ContinueButton {
72+
Layout.preferredWidth: Math.min(300, columnLayout.width - 2 * Layout.leftMargin)
73+
Layout.topMargin: 40
74+
Layout.leftMargin: 20
75+
Layout.rightMargin: Layout.leftMargin
76+
Layout.bottomMargin: 20
77+
Layout.alignment: Qt.AlignCenter
78+
text: qsTr("Choose snapshot file")
79+
enabled: headersSynced
80+
onClicked: fileDialog.open()
81+
}
82+
83+
FileDialog {
84+
id: fileDialog
85+
folder: shortcuts.home
86+
selectMultiple: false
87+
selectExisting: true
88+
nameFilters: ["Snapshot files (*.dat)", "All files (*)"]
89+
onAccepted: {
90+
selectedFile = fileUrl.toString()
91+
snapshotFileName = selectedFile
92+
if (!nodeModel.snapshotLoadThread(snapshotFileName)) {
93+
snapshotError = true
94+
}
95+
}
96+
}
97+
}
98+
99+
ColumnLayout {
100+
Layout.alignment: Qt.AlignHCenter
101+
Layout.preferredWidth: Math.min(parent.width, 450)
102+
103+
Image {
104+
Layout.alignment: Qt.AlignCenter
105+
source: "image://images/circle-file"
106+
107+
sourceSize.width: 200
108+
sourceSize.height: 200
109+
}
110+
111+
Header {
112+
Layout.fillWidth: true
113+
Layout.topMargin: 20
114+
Layout.leftMargin: 20
115+
Layout.rightMargin: 20
116+
header: qsTr("Loading Snapshot")
117+
description: qsTr("This might take a while...")
118+
}
119+
120+
ProgressIndicator {
121+
id: progressIndicator
122+
Layout.topMargin: 20
123+
width: 200
124+
height: 20
125+
progress: nodeModel.snapshotProgress
126+
Layout.alignment: Qt.AlignCenter
127+
progressColor: Theme.color.blue
128+
}
129+
}
130+
131+
ColumnLayout {
132+
id: loadedSnapshotColumn
133+
Layout.alignment: Qt.AlignHCenter
134+
Layout.preferredWidth: Math.min(parent.width, 450)
135+
136+
Image {
137+
Layout.alignment: Qt.AlignCenter
138+
source: "image://images/circle-green-check"
139+
140+
sourceSize.width: 60
141+
sourceSize.height: 60
142+
}
143+
144+
Header {
145+
Layout.fillWidth: true
146+
Layout.topMargin: 20
147+
headerBold: true
148+
header: qsTr("Snapshot Loaded")
149+
descriptionBold: false
150+
descriptionColor: Theme.color.neutral6
151+
descriptionSize: 17
152+
descriptionLineHeight: 1.1
153+
description: snapshotInfo && snapshotInfo["date"] ?
154+
qsTr("It contains unspent transactions up to %1. Next, transactions will be verified and newer transactions downloaded.").arg(snapshotInfo["date"]) :
155+
qsTr("It contains transactions up to DEBUG. Newer transactions still need to be downloaded." +
156+
" The data will be verified in the background.")
157+
}
158+
159+
ContinueButton {
160+
Layout.preferredWidth: Math.min(300, columnLayout.width - 2 * Layout.leftMargin)
161+
Layout.topMargin: 40
162+
Layout.alignment: Qt.AlignCenter
163+
text: qsTr("Done")
164+
onClicked: {
165+
chainModel.isSnapshotActiveChanged()
166+
back()
167+
}
168+
}
169+
170+
Setting {
171+
id: viewDetails
172+
Layout.alignment: Qt.AlignCenter
173+
header: qsTr("View details")
174+
actionItem: CaretRightIcon {
175+
id: caretIcon
176+
color: viewDetails.stateColor
177+
rotation: viewDetails.expanded ? 90 : 0
178+
Behavior on rotation { NumberAnimation { duration: 200 } }
179+
}
180+
181+
property bool expanded: false
182+
183+
onClicked: {
184+
expanded = !expanded
185+
}
186+
}
187+
188+
ColumnLayout {
189+
id: detailsContent
190+
visible: viewDetails.expanded
191+
Layout.preferredWidth: Math.min(300, parent.width - 2 * Layout.leftMargin)
192+
Layout.alignment: Qt.AlignCenter
193+
Layout.leftMargin: 80
194+
Layout.rightMargin: 80
195+
Layout.topMargin: 10
196+
spacing: 10
197+
// TODO: make sure the block height number aligns right
198+
RowLayout {
199+
CoreText {
200+
text: qsTr("Block Height:")
201+
Layout.alignment: Qt.AlignLeft
202+
font.pixelSize: 14
203+
}
204+
CoreText {
205+
text: snapshotInfo && snapshotInfo["height"] ?
206+
snapshotInfo["height"] : qsTr("DEBUG")
207+
Layout.alignment: Qt.AlignRight
208+
font.pixelSize: 14
209+
}
210+
}
211+
Separator { Layout.fillWidth: true }
212+
ColumnLayout {
213+
Layout.fillWidth: true
214+
spacing: 5
215+
CoreText {
216+
text: qsTr("Hash:")
217+
font.pixelSize: 14
218+
}
219+
CoreText {
220+
text: snapshotInfo && snapshotInfo["hashSerializedFirstHalf"] ?
221+
snapshotInfo["hashSerializedFirstHalf"] + "\n" + snapshotInfo["hashSerializedSecondHalf"] :
222+
qsTr("DEBUG")
223+
Layout.fillWidth: true
224+
font.pixelSize: 14
225+
textFormat: Text.PlainText
226+
}
227+
}
228+
}
229+
}
230+
231+
ColumnLayout {
232+
id: snapshotErrorColumn
233+
Layout.alignment: Qt.AlignHCenter
234+
Layout.preferredWidth: Math.min(parent.width, 450)
235+
236+
Image {
237+
Layout.alignment: Qt.AlignCenter
238+
source: "image://images/circle-red-cross"
239+
240+
sourceSize.width: 60
241+
sourceSize.height: 60
242+
}
243+
244+
Header {
245+
Layout.fillWidth: true
246+
Layout.topMargin: 20
247+
headerBold: true
248+
header: qsTr("Snapshot Could Not Be Verified")
249+
descriptionBold: false
250+
descriptionColor: Theme.color.neutral6
251+
descriptionSize: 17
252+
descriptionLineHeight: 1.1
253+
description: qsTr("There was a problem with the transactions in the snapshot. Please try a different file.")
254+
}
255+
256+
ContinueButton {
257+
Layout.preferredWidth: Math.min(300, columnLayout.width - 2 * Layout.leftMargin)
258+
Layout.topMargin: 40
259+
Layout.alignment: Qt.AlignCenter
260+
text: qsTr("OK")
261+
onClicked: {
262+
snapshotError = false
263+
back()
264+
}
265+
}
266+
}
267+
}
268+
}

src/qml/controls/GreenCheckIcon.qml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright (c) 2023 - present 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+
import QtQuick 2.15
6+
import QtQuick.Controls 2.15
7+
8+
Icon {
9+
source: "image://images/green-check"
10+
size: 30
11+
}

0 commit comments

Comments
 (0)