Skip to content

Commit

Permalink
Merge #428: Migrate to PageStacks
Browse files Browse the repository at this point in the history
c52566d qml: Swap existing SwipeViews for PageStack (jarolrod)
f0e5951 qml: Swap existing StackViews for PageStack (jarolrod)
7ba2f62 qml: declare OnboardingWizard file, reintroduce as PageStack (jarolrod)
d49b888 qml: Introduce PageStack control (jarolrod)

Pull request description:

  After fixing our sins in #427, migrating to A StackView based GUI is quite simple.

  Here we use a custom StackView control, PageStack, that has a property `vertical` used to declare if we want vertical or horizontal animations, and additionally implements the [custom animation](#422) we want.

  Closes #422
  Closes #219

  [![Build Artifacts](https://img.shields.io/badge/Build%20Artifacts-green
  )]()

ACKs for top commit:
  pablomartin4btc:
    re-ACK c52566d
  MarnixCroes:
    tACK c52566d
  D33r-Gee:
    tACK  [c52566d](c52566d) Works as expected on WSL Ubuntu 22.04
  johnny9:
    ACK c52566d

Tree-SHA512: f9a025944db24a46e1f78f4ad8a9b9aca4e1f3ff4dd5927eebfa2a7fb28ed390a17da79e23c6248c3c0e82b361ff1b2dedbf4df9df2a1d0677b05bacb7763bcb
hebasto committed Nov 24, 2024
2 parents 15c1f39 + c52566d commit 574817b
Showing 15 changed files with 397 additions and 269 deletions.
2 changes: 2 additions & 0 deletions src/Makefile.qt.include
Original file line number Diff line number Diff line change
@@ -398,6 +398,7 @@ QML_RES_QML = \
qml/controls/OptionButton.qml \
qml/controls/OptionSwitch.qml \
qml/controls/OutlineButton.qml \
qml/controls/PageStack.qml \
qml/controls/ProgressIndicator.qml \
qml/controls/qmldir \
qml/controls/Setting.qml \
@@ -420,6 +421,7 @@ QML_RES_QML = \
qml/pages/onboarding/OnboardingStorageAmount.qml \
qml/pages/onboarding/OnboardingStorageLocation.qml \
qml/pages/onboarding/OnboardingStrengthen.qml \
qml/pages/onboarding/OnboardingWizard.qml \
qml/pages/settings/SettingsAbout.qml \
qml/pages/settings/SettingsBlockClockDisplayMode.qml \
qml/pages/settings/SettingsConnection.qml \
2 changes: 2 additions & 0 deletions src/qml/bitcoin_qml.qrc
Original file line number Diff line number Diff line change
@@ -38,6 +38,7 @@
<file>controls/OptionButton.qml</file>
<file>controls/OptionSwitch.qml</file>
<file>controls/OutlineButton.qml</file>
<file>controls/PageStack.qml</file>
<file>controls/ProgressIndicator.qml</file>
<file>controls/qmldir</file>
<file>controls/Setting.qml</file>
@@ -60,6 +61,7 @@
<file>pages/onboarding/OnboardingStorageAmount.qml</file>
<file>pages/onboarding/OnboardingStorageLocation.qml</file>
<file>pages/onboarding/OnboardingStrengthen.qml</file>
<file>pages/onboarding/OnboardingWizard.qml</file>
<file>pages/settings/SettingsAbout.qml</file>
<file>pages/settings/SettingsBlockClockDisplayMode.qml</file>
<file>pages/settings/SettingsConnection.qml</file>
51 changes: 51 additions & 0 deletions src/qml/controls/PageStack.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright (c) 2024 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

import QtQuick 2.15
import QtQuick.Controls 2.15

StackView {
property bool vertical: false

pushEnter: Transition {
NumberAnimation {
property: vertical ? "y" : "x"
from: vertical ? parent.height : parent.width
to: 0
duration: 400
easing.type: Easing.Bezier
easing.bezierCurve: [0.5, 0.0, 0.2, 1.0]
}
}
pushExit: Transition {
NumberAnimation {
property: vertical ? "y" : "x"
from: 0
to: vertical ? -parent.height : -parent.width
duration: 400
easing.type: Easing.Bezier
easing.bezierCurve: [0.5, 0.0, 0.2, 1.0]
}
}
popEnter: Transition {
NumberAnimation {
property: vertical ? "y" : "x"
from: vertical ? -parent.height : -parent.width
to: 0
duration: 400
easing.type: Easing.Bezier
easing.bezierCurve: [0.5, 0.0, 0.2, 1.0]
}
}
popExit: Transition {
NumberAnimation {
property: vertical ? "y" : "x"
from: 0
to: vertical ? parent.height : parent.width
duration: 400
easing.type: Easing.Bezier
easing.bezierCurve: [0.5, 0.0, 0.2, 1.0]
}
}
}
60 changes: 19 additions & 41 deletions src/qml/pages/main.qml
Original file line number Diff line number Diff line change
@@ -32,7 +32,7 @@ ApplicationWindow {
ColorAnimation { duration: 150 }
}

StackView {
PageStack {
id: main
initialItem: {
if (needOnboarding) {
@@ -65,36 +65,8 @@ ApplicationWindow {

Component {
id: onboardingWizard
SwipeView {
id: swipeView
property bool finished: false
interactive: false

OnboardingCover {
onNext: swipeView.incrementCurrentIndex()
}
OnboardingStrengthen {
onBack: swipeView.decrementCurrentIndex()
onNext: swipeView.incrementCurrentIndex()
}
OnboardingBlockclock {
onBack: swipeView.decrementCurrentIndex()
onNext: swipeView.incrementCurrentIndex()
}
OnboardingStorageLocation {
onBack: swipeView.decrementCurrentIndex()
onNext: swipeView.incrementCurrentIndex()
}
OnboardingStorageAmount {
onBack: swipeView.decrementCurrentIndex()
onNext: swipeView.incrementCurrentIndex()
}
OnboardingConnection {
onBack: swipeView.decrementCurrentIndex()
onNext: swipeView.finished = true
}

onFinishedChanged: {
OnboardingWizard {
onFinished: {
optionsModel.onboard()
if (AppMode.walletEnabled && AppMode.isDesktop) {
main.push(desktopWallets)
@@ -127,18 +99,24 @@ ApplicationWindow {

Component {
id: node
SwipeView {
id: node_swipe
interactive: false
orientation: Qt.Vertical
NodeRunner {
onSettingsClicked: {
node_swipe.incrementCurrentIndex()
PageStack {
id: nodeStack
vertical: true
initialItem: node
Component {
id: node
NodeRunner {
onSettingsClicked: {
nodeStack.push(nodeSettings)
}
}
}
NodeSettings {
onDoneClicked: {
node_swipe.decrementCurrentIndex()
Component {
id: nodeSettings
NodeSettings {
onDoneClicked: {
nodeStack.pop()
}
}
}
}
2 changes: 1 addition & 1 deletion src/qml/pages/node/NodeSettings.qml
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@ Item {

id: root

StackView {
PageStack {
id: nodeSettingsView
anchors.fill: parent

76 changes: 41 additions & 35 deletions src/qml/pages/onboarding/OnboardingConnection.qml
Original file line number Diff line number Diff line change
@@ -15,46 +15,52 @@ Page {
signal next
background: null
clip: true
SwipeView {
id: connections
PageStack {
id: connectionStack
anchors.fill: parent
interactive: false
orientation: Qt.Vertical
InformationPage {
navLeftDetail: NavButton {
iconSource: "image://images/caret-left"
text: qsTr("Back")
onClicked: root.back()
}
bannerItem: Image {
Layout.topMargin: 20
Layout.alignment: Qt.AlignCenter
source: Theme.image.storage
sourceSize.width: 200
sourceSize.height: 200
}
bold: true
headerText: qsTr("Starting initial download")
headerMargin: 30
description: qsTr("The application will connect to the Bitcoin network and start downloading and verifying transactions.\n\nThis may take several hours, or even days, based on your connection.")
descriptionMargin: 10
detailActive: true
detailTopMargin: 10
detailItem: RowLayout {
TextButton {
vertical: true
initialItem: onboardingConnection
Component {
id: onboardingConnection
InformationPage {
navLeftDetail: NavButton {
iconSource: "image://images/caret-left"
text: qsTr("Back")
onClicked: root.back()
}
bannerItem: Image {
Layout.topMargin: 20
Layout.alignment: Qt.AlignCenter
text: qsTr("Connection settings")
onClicked: connections.incrementCurrentIndex()
source: Theme.image.storage
sourceSize.width: 200
sourceSize.height: 200
}
bold: true
headerText: qsTr("Starting initial download")
headerMargin: 30
description: qsTr("The application will connect to the Bitcoin network and start downloading and verifying transactions.\n\nThis may take several hours, or even days, based on your connection.")
descriptionMargin: 10
detailActive: true
detailTopMargin: 10
detailItem: RowLayout {
TextButton {
Layout.alignment: Qt.AlignCenter
text: qsTr("Connection settings")
onClicked: connectionStack.push(connectionSettings)
}
}
lastPage: true
buttonText: qsTr("Next")
buttonMargin: 20
onNext: root.next()
}
lastPage: true
buttonText: qsTr("Next")
buttonMargin: 20
onNext: root.next()
}
SettingsConnection {
onboarding: true
onBack: connections.decrementCurrentIndex()
Component {
id: connectionSettings
SettingsConnection {
onboarding: true
onBack: connectionStack.pop()
}
}
}
}
75 changes: 39 additions & 36 deletions src/qml/pages/onboarding/OnboardingCover.qml
Original file line number Diff line number Diff line change
@@ -14,47 +14,50 @@ Page {
signal next
background: null
clip: true
SwipeView {
id: introductions
PageStack {
id: coverStack
anchors.fill: parent
interactive: false
orientation: Qt.Horizontal
InformationPage {
navRightDetail: NavButton {
iconSource: "image://images/info"
iconHeight: 24
iconWidth: 24
iconColor: Theme.color.neutral0
iconBackground: Rectangle {
radius: 12
color: Theme.color.neutral9
initialItem: onboardingCover
Component {
id: onboardingCover
InformationPage {
navRightDetail: NavButton {
iconSource: "image://images/info"
iconHeight: 24
iconWidth: 24
iconColor: Theme.color.neutral0
iconBackground: Rectangle {
radius: 12
color: Theme.color.neutral9
}
onClicked: coverStack.push(coverSettings)
}
onClicked: {
introductions.incrementCurrentIndex()
bannerItem: Image {
Layout.fillWidth: true
Layout.alignment: Qt.AlignCenter
source: "image://images/app"
// Bitcoin icon has ~11% padding
sourceSize.width: 112
sourceSize.height: 112
}
bannerMargin: 0
bold: true
headerText: qsTr("Bitcoin Core App")
headerSize: 36
description: qsTr("Be part of the Bitcoin network.")
descriptionMargin: 10
descriptionSize: 24
subtext: qsTr("100% open-source & open-design")
buttonText: qsTr("Start")
onNext: root.next()
}
bannerItem: Image {
Layout.fillWidth: true
Layout.alignment: Qt.AlignCenter
source: "image://images/app"
// Bitcoin icon has ~11% padding
sourceSize.width: 112
sourceSize.height: 112
}
bannerMargin: 0
bold: true
headerText: qsTr("Bitcoin Core App")
headerSize: 36
description: qsTr("Be part of the Bitcoin network.")
descriptionMargin: 10
descriptionSize: 24
subtext: qsTr("100% open-source & open-design")
buttonText: qsTr("Start")
onNext: root.next()
}
SettingsAbout {
onboarding: true
onBack: introductions.decrementCurrentIndex()
Component {
id: coverSettings
SettingsAbout {
onboarding: true
onBack: coverStack.pop()
}
}
}
}
86 changes: 50 additions & 36 deletions src/qml/pages/onboarding/OnboardingStorageAmount.qml
Original file line number Diff line number Diff line change
@@ -13,49 +13,63 @@ Page {
id: root
signal back
signal next
property bool customStorage: false
property int customStorageAmount
background: null
clip: true
SwipeView {
id: storages
PageStack {
id: stack
anchors.fill: parent
interactive: false
orientation: Qt.Vertical
InformationPage {
navLeftDetail: NavButton {
iconSource: "image://images/caret-left"
text: qsTr("Back")
onClicked: root.back()
}
bannerActive: false
bold: true
headerText: qsTr("Storage")
headerMargin: 0
description: qsTr("Data retrieved from the Bitcoin network is stored on your device.\nYou have 500GB of storage available.")
descriptionMargin: 10
detailActive: true
detailItem: ColumnLayout {
spacing: 0
StorageOptions {
customStorage: advancedStorage.loadedDetailItem.customStorage
customStorageAmount: advancedStorage.loadedDetailItem.customStorageAmount
Layout.maximumWidth: 450
Layout.alignment: Qt.AlignCenter
vertical: true
initialItem: onboardingStorageAmount
Component {
id: onboardingStorageAmount
InformationPage {
navLeftDetail: NavButton {
iconSource: "image://images/caret-left"
text: qsTr("Back")
onClicked: root.back()
}
TextButton {
Layout.topMargin: 10
Layout.alignment: Qt.AlignCenter
text: qsTr("Detailed settings")
onClicked: storages.incrementCurrentIndex()
bannerActive: false
bold: true
headerText: qsTr("Storage")
headerMargin: 0
description: qsTr("Data retrieved from the Bitcoin network is stored on your device.\nYou have 500GB of storage available.")
descriptionMargin: 10
detailActive: true
detailItem: ColumnLayout {
spacing: 0
StorageOptions {
customStorage: advancedStorage.loadedDetailItem.customStorage
customStorageAmount: advancedStorage.loadedDetailItem.customStorageAmount
Layout.maximumWidth: 450
Layout.alignment: Qt.AlignCenter
}
TextButton {
Layout.topMargin: 10
Layout.alignment: Qt.AlignCenter
text: qsTr("Detailed settings")
onClicked: stack.push(storageAmountSettings)
}
}
buttonText: qsTr("Next")
buttonMargin: 20
onNext: root.next()
}
buttonText: qsTr("Next")
buttonMargin: 20
onNext: root.next()
}
SettingsStorage {
id: advancedStorage
onboarding: true
onBack: storages.decrementCurrentIndex()
Component {
id: storageAmountSettings
SettingsStorage {
id: advancedStorage
onboarding: true
onBack: stack.pop()
onCustomStorageChanged: {
root.customStorage = advancedStorage.customStorage
}
onCustomStorageAmountChanged: {
root.customStorageAmount = advancedStorage.customStorageAmount
}
}
}
}
}
57 changes: 57 additions & 0 deletions src/qml/pages/onboarding/OnboardingWizard.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright (c) 2024 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import "../../controls"

PageStack {
id: root

signal finished()
initialItem: cover

Component {
id: cover
OnboardingCover {
onNext: root.push(strengthen)
}
}
Component {
id: strengthen
OnboardingStrengthen {
onBack: root.pop()
onNext: root.push(blockclock)
}
}
Component {
id: blockclock
OnboardingBlockclock {
onBack: root.pop()
onNext: root.push(storageLocation)
}
}
Component {
id: storageLocation
OnboardingStorageLocation {
onBack: root.pop()
onNext: root.push(storageAmount)
}
}
Component {
id: storageAmount
OnboardingStorageAmount {
onBack: root.pop()
onNext: root.push(connection)
}
}
Component {
id: connection
OnboardingConnection {
onBack: root.pop()
onNext: root.finished()
}
}
}
111 changes: 58 additions & 53 deletions src/qml/pages/settings/SettingsAbout.qml
Original file line number Diff line number Diff line change
@@ -8,70 +8,75 @@ import QtQuick.Layouts 1.15
import "../../controls"
import "../../components"

Item {
Page {
id: root
signal back
property bool onboarding: false
SwipeView {
id: aboutSwipe
background: null
PageStack {
id: stack
anchors.fill: parent
interactive: false
orientation: Qt.Horizontal
InformationPage {
id: about_settings
bannerActive: false
bannerMargin: 0
bold: true
showHeader: root.onboarding
headerText: qsTr("About")
headerMargin: 0
description: qsTr("Bitcoin Core is an open source project.\nIf you find it useful, please contribute.\n\n This is experimental software.")
descriptionMargin: 20
detailActive: true
detailItem: AboutOptions {
onNext: aboutSwipe.incrementCurrentIndex()
}
initialItem: aboutPage
Component {
id: aboutPage
InformationPage {
id: about_settings
bannerActive: false
bannerMargin: 0
bold: true
showHeader: root.onboarding
headerText: qsTr("About")
headerMargin: 0
description: qsTr("Bitcoin Core is an open source project.\nIf you find it useful, please contribute.\n\n This is experimental software.")
descriptionMargin: 20
detailActive: true
detailItem: AboutOptions {
onNext: stack.push(developerSettings)
}

states: [
State {
when: root.onboarding
PropertyChanges {
target: about_settings
navLeftDetail: backButton
navMiddleDetail: null
states: [
State {
when: root.onboarding
PropertyChanges {
target: about_settings
navLeftDetail: backButton
navMiddleDetail: null
}
},
State {
when: !root.onboarding
PropertyChanges {
target: about_settings
navLeftDetail: backButton
navMiddleDetail: header
}
}
},
State {
when: !root.onboarding
PropertyChanges {
target: about_settings
navLeftDetail: backButton
navMiddleDetail: header
}
}
]
]

Component {
id: backButton
NavButton {
iconSource: "image://images/caret-left"
text: qsTr("Back")
onClicked: root.back()
Component {
id: backButton
NavButton {
iconSource: "image://images/caret-left"
text: qsTr("Back")
onClicked: root.back()
}
}
}
Component {
id: header
Header {
headerBold: true
headerSize: 18
header: qsTr("About")
Component {
id: header
Header {
headerBold: true
headerSize: 18
header: qsTr("About")
}
}
}
}
SettingsDeveloper {
id: about_developer
onboarding: root.onboarding
onBack: aboutSwipe.decrementCurrentIndex()
Component {
id: developerSettings
SettingsDeveloper {
onboarding: root.onboarding
onBack: stack.pop()
}
}
}
}
124 changes: 64 additions & 60 deletions src/qml/pages/settings/SettingsConnection.qml
Original file line number Diff line number Diff line change
@@ -8,79 +8,83 @@ import QtQuick.Layouts 1.15
import "../../controls"
import "../../components"

Item {
Page {
id: root
signal back
property bool onboarding: false
SwipeView {
id: connectionSwipe
property bool onboarding: false
background: null
PageStack {
id: stack
anchors.fill: parent
interactive: false
orientation: Qt.Horizontal
InformationPage {
id: connection_settings
background: null
clip: true
bannerActive: false
bold: true
showHeader: root.onboarding
headerText: qsTr("Connection settings")
headerMargin: 0
detailActive: true
detailItem: ConnectionSettings {
onNext: connectionSwipe.incrementCurrentIndex()
}
initialItem: connectionSettings
Component {
id: connectionSettings
InformationPage {
id: connection_settings
background: null
clip: true
bannerActive: false
bold: true
showHeader: root.onboarding
headerText: qsTr("Connection settings")
headerMargin: 0
detailActive: true
detailItem: ConnectionSettings {
onNext: stack.push(proxySettings)
}

states: [
State {
when: root.onboarding
PropertyChanges {
target: connection_settings
navLeftDetail: null
navMiddleDetail: null
navRightDetail: doneButton
}
},
State {
when: !root.onboarding
PropertyChanges {
target: connection_settings
navLeftDetail: backButton
navMiddleDetail: header
navRightDetail: null
states: [
State {
when: root.onboarding
PropertyChanges {
target: connection_settings
navLeftDetail: null
navMiddleDetail: null
navRightDetail: doneButton
}
},
State {
when: !root.onboarding
PropertyChanges {
target: connection_settings
navLeftDetail: backButton
navMiddleDetail: header
navRightDetail: null
}
}
}
]

Component {
id: backButton
NavButton {
iconSource: "image://images/caret-left"
text: qsTr("Back")
onClicked: root.back()
]

Component {
id: backButton
NavButton {
iconSource: "image://images/caret-left"
text: qsTr("Back")
onClicked: root.back()
}
}
}
Component {
id: header
Header {
headerBold: true
headerSize: 18
header: qsTr("Connection settings")
Component {
id: header
Header {
headerBold: true
headerSize: 18
header: qsTr("Connection settings")
}
}
}

Component {
id: doneButton
NavButton {
text: qsTr("Done")
onClicked: root.back()
Component {
id: doneButton
NavButton {
text: qsTr("Done")
onClicked: root.back()
}
}
}
}
SettingsProxy {
onBack: {
connectionSwipe.decrementCurrentIndex()
Component {
id: proxySettings
SettingsProxy {
onBack: stack.pop()
}
}
}
2 changes: 1 addition & 1 deletion src/qml/pages/settings/SettingsDisplay.qml
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@ Item {

id: root

StackView {
PageStack {
id: displaySettingsView
anchors.fill: parent

4 changes: 0 additions & 4 deletions src/qml/pages/settings/SettingsProxy.qml
Original file line number Diff line number Diff line change
@@ -14,10 +14,6 @@ Page {
id: root

background: null
implicitWidth: 450
leftPadding: 20
rightPadding: 20
topPadding: 30

header: NavigationBar2 {
leftItem: NavButton {
12 changes: 11 additions & 1 deletion src/qml/pages/settings/SettingsStorage.qml
Original file line number Diff line number Diff line change
@@ -10,14 +10,24 @@ import "../../components"

InformationPage {
id: root
property bool customStorage: false
property bool customStorageAmount
property bool onboarding: false
bannerActive: false
bold: true
showHeader: root.onboarding
headerText: qsTr("Storage settings")
headerMargin: 0
detailActive: true
detailItem: StorageSettings {}
detailItem: StorageSettings {
id: storageSettings
onCustomStorageChanged: {
root.customStorage = storageSettings.customStorage
}
onCustomStorageAmountChanged: {
root.customStorageAmount = storageSettings.customStorageAmount
}
}
states: [
State {
when: root.onboarding
2 changes: 1 addition & 1 deletion src/qml/pages/wallet/CreateWalletWizard.qml
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@ import "../../components"
import "../settings"
import "../wallet"

StackView {
PageStack {
id: root

signal finished()

0 comments on commit 574817b

Please sign in to comment.