Add nice onboarding

This commit is contained in:
Arnaud 2026-02-20 15:07:58 +04:00
parent 16d16de3c7
commit a7d1e092a3
No known key found for this signature in database
GPG Key ID: 20E40A5D3110766F
8 changed files with 228 additions and 63 deletions

View File

@ -772,8 +772,6 @@ StorageBackend::StorageStatus StorageBackend::status() const { return m_status;
QString StorageBackend::cid() const { return m_cid; }
QString StorageBackend::configJson() const { return QString::fromUtf8(m_config.toJson(QJsonDocument::Compact)); }
int StorageBackend::uploadProgress() const { return m_uploadProgress; }
QString StorageBackend::uploadStatus() const { return m_uploadStatus; }
@ -824,7 +822,7 @@ void StorageBackend::reloadIfChanged(const QString& configJson) {
void StorageBackend::saveCurrentConfig() {
qDebug() << "StorageBackend::saveUserConfig";
saveUserConfig(QString::fromUtf8(m_config.toJson(QJsonDocument::Compact)));
saveUserConfig(QString::fromUtf8(m_config.toJson(QJsonDocument::Indented)));
}
void StorageBackend::saveUserConfig(const QString& configJson) {
@ -865,7 +863,7 @@ void StorageBackend::enableUpnpConfig() {
obj["nat"] = "upnp";
reloadIfChanged(QString::fromUtf8(QJsonDocument(obj).toJson(QJsonDocument::Compact)));
reloadIfChanged(QString::fromUtf8(QJsonDocument(obj).toJson(QJsonDocument::Indented)));
}
void StorageBackend::enableNatExtConfig(int tcpPort) {
@ -1013,7 +1011,7 @@ void StorageBackend::loadUserConfig() {
result = init(QString::fromUtf8(file.readAll()));
} else {
qWarning() << "StorageBackend::loadUserConfig Failed to read the user config file, fallback to default config";
result = init(QString::fromUtf8(defaultConfig().toJson(QJsonDocument::Compact)));
result = init(QString::fromUtf8(defaultConfig().toJson(QJsonDocument::Indented)));
}
if (!result.success) {

View File

@ -62,7 +62,6 @@ class StorageBackend : public QObject {
QString cid() const;
QString debugLogs() const;
StorageStatus status() const;
QString configJson() const;
int uploadProgress() const;
QString uploadStatus() const;
QVariantList manifests() const;

View File

@ -10,7 +10,7 @@ LogosStorageLayout {
property var backend: null
signal back
signal completed(string configJson)
signal completed
ColumnLayout {
anchors.fill: parent
@ -56,7 +56,8 @@ LogosStorageLayout {
property bool isValid: true
Component.onCompleted: {
text = (root.backend && root.backend.configJson) ? root.backend.configJson : "{}"
text = (root.backend
&& root.backend.configJson) ? root.backend.configJson : "{}"
validate()
}
@ -102,7 +103,11 @@ LogosStorageLayout {
anchors.fill: parent
enabled: jsonArea.isValid
cursorShape: jsonArea.isValid ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: root.completed(jsonArea.text)
onClicked: function () {
root.backend.saveUserConfig(jsonArea.text)
root.backend.reloadIfChanged(jsonArea.text)
root.completed()
}
}
}
}

View File

@ -136,6 +136,8 @@ qt_add_qml_module(appqml
PortForwarding.qml
ErrorToast.qml
HealthIndicator.qml
ModeSelector.qml
AdvancedSetup.qml
)
# Set up QML module directory for runtime

View File

@ -33,12 +33,12 @@ Item {
// and click on "Back",
// In that case, we pop the navigation after
// the node is stopped.
function onStopCompleted() {
if (!settings.onboardingCompleted) {
// function onStopCompleted() {
// if (!settings.onboardingCompleted) {
// stackView.pop()
}
}
// // stackView.pop()
// }
// }
// When the onboarding is completed,
// the user should have a config save in his
@ -49,7 +49,6 @@ Item {
function onReady() {
if (settings.onboardingCompleted) {
root.backend.loadUserConfig()
root.backend.start()
stackView.replace(storageComponent, StackView.Immediate)
}
}
@ -70,7 +69,21 @@ Item {
StackView {
id: stackView
anchors.fill: parent
initialItem: onboardingComponent
initialItem: modeSelectorComponent
}
Component {
id: modeSelectorComponent
ModeSelector {
onCompleted: function (isGuide) {
if (isGuide) {
stackView.push(onboardingComponent)
} else {
stackView.push(advancedSetupComponent)
}
}
}
}
Component {
@ -79,8 +92,8 @@ Item {
OnBoarding {
backend: root.backend
// The completed event means the user
// selected upup or port forwarding.
onBack: stackView.pop()
onCompleted: function (upnpEnabled) {
if (upnpEnabled) {
stackView.push(startNodeComponent)
@ -91,6 +104,21 @@ Item {
}
}
Component {
id: advancedSetupComponent
AdvancedSetup {
backend: root.backend
onBack: stackView.pop()
onCompleted: function () {
settings.onboardingCompleted = true
stackView.replace(storageComponent, StackView.Immediate)
}
}
}
Component {
id: storageComponent

View File

@ -43,28 +43,25 @@ LogosStorageLayout {
width: 190
height: 230
radius: 14
color: root.selectedMode === 0 ? Qt.rgba(1, 1, 1, 0.08) : "transparent"
border.color: root.selectedMode === 0 ? "white" : Qt.rgba(1, 1, 1, 0.2)
color: root.selectedMode === 0 ? Qt.rgba(1, 1, 1,
0.08) : "transparent"
border.color: root.selectedMode === 0 ? "white" : Qt.rgba(1, 1,
1,
0.2)
border.width: root.selectedMode === 0 ? 2 : 1
ColumnLayout {
anchors.centerIn: parent
spacing: 14
// Nothing OS dot icon crosshair/compass
// Nothing OS dot icon like
Grid {
columns: 5
spacing: 4
Layout.alignment: Qt.AlignHCenter
Repeater {
model: [
0, 0, 1, 0, 0,
0, 0, 1, 0, 0,
1, 1, 0, 1, 1,
0, 0, 1, 0, 0,
0, 0, 1, 0, 0
]
model: [0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0]
Rectangle {
width: 6
height: 6
@ -106,28 +103,25 @@ LogosStorageLayout {
width: 190
height: 230
radius: 14
color: root.selectedMode === 1 ? Qt.rgba(1, 1, 1, 0.08) : "transparent"
border.color: root.selectedMode === 1 ? "white" : Qt.rgba(1, 1, 1, 0.2)
color: root.selectedMode === 1 ? Qt.rgba(1, 1, 1,
0.08) : "transparent"
border.color: root.selectedMode === 1 ? "white" : Qt.rgba(1, 1,
1,
0.2)
border.width: root.selectedMode === 1 ? 2 : 1
ColumnLayout {
anchors.centerIn: parent
spacing: 14
// Nothing OS dot icon X pattern
// Nothing OS dot icon like
Grid {
columns: 5
spacing: 4
Layout.alignment: Qt.AlignHCenter
Repeater {
model: [
1, 0, 0, 0, 1,
0, 1, 0, 1, 0,
0, 0, 1, 0, 0,
0, 1, 0, 1, 0,
1, 0, 0, 0, 1
]
model: [1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1]
Rectangle {
width: 6
height: 6

View File

@ -1,5 +1,4 @@
import QtQuick
import QtQuick.Dialogs
import QtQuick.Layouts
import Logos.Theme
import Logos.Controls
@ -9,49 +8,187 @@ LogosStorageLayout {
property var backend: mockBackend
signal completed(bool enabled)
signal back
signal completed(bool upnpEnabled)
property int selectedMode: -1 // 0 = upnp, 1 = port forwarding
ColumnLayout {
spacing: Theme.spacing.medium
Layout.fillWidth: true
anchors.centerIn: parent
spacing: Theme.spacing.medium
width: 430
LogosText {
id: titleText
text: "Network Configuration"
font.pixelSize: Theme.typography.titleText
text: "Welcome to Logos Storage"
Layout.alignment: Qt.AlignCenter
Layout.alignment: Qt.AlignHCenter
}
LogosText {
id: questionText
font.pixelSize: Theme.typography.titleText
text: "Is UPnP enabled on your router ?"
Layout.alignment: Qt.AlignCenter
}
LogosText {
id: questionDescriptionText
text: "How is your network configured?"
font.pixelSize: Theme.typography.primaryText
text: "UPnP simplifies configuration by handling port forwarding automatically."
Layout.alignment: Qt.AlignCenter
Layout.alignment: Qt.AlignHCenter
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
Layout.fillWidth: true
}
Item {
height: Theme.spacing.medium
}
Row {
spacing: Theme.spacing.medium
Layout.alignment: Qt.AlignHCenter
// UPnP card
Rectangle {
width: 190
height: 230
radius: 14
color: root.selectedMode === 0 ? Qt.rgba(1, 1, 1, 0.08) : "transparent"
border.color: root.selectedMode === 0 ? "white" : Qt.rgba(1, 1, 1, 0.2)
border.width: root.selectedMode === 0 ? 2 : 1
ColumnLayout {
anchors.centerIn: parent
spacing: 14
// Nothing OS dot icon diamond/network
Grid {
columns: 5
spacing: 4
Layout.alignment: Qt.AlignHCenter
Repeater {
model: [
0, 0, 1, 0, 0,
0, 1, 0, 1, 0,
1, 0, 1, 0, 1,
0, 1, 0, 1, 0,
0, 0, 1, 0, 0
]
Rectangle {
width: 6
height: 6
radius: 2
color: "white"
opacity: modelData ? 0.9 : 0.1
}
}
}
Text {
text: "UPnP"
color: "white"
font.pixelSize: 16
font.bold: true
Layout.alignment: Qt.AlignHCenter
}
Text {
text: "Automatic port\nforwarding via\nUPnP router."
color: Qt.rgba(1, 1, 1, 0.55)
font.pixelSize: 12
horizontalAlignment: Text.AlignHCenter
Layout.alignment: Qt.AlignHCenter
Layout.preferredWidth: 150
wrapMode: Text.WordWrap
}
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: root.selectedMode = 0
}
}
// Port Forwarding card
Rectangle {
width: 190
height: 230
radius: 14
color: root.selectedMode === 1 ? Qt.rgba(1, 1, 1, 0.08) : "transparent"
border.color: root.selectedMode === 1 ? "white" : Qt.rgba(1, 1, 1, 0.2)
border.width: root.selectedMode === 1 ? 2 : 1
ColumnLayout {
anchors.centerIn: parent
spacing: 14
// Nothing OS dot icon right arrow
Grid {
columns: 5
spacing: 4
Layout.alignment: Qt.AlignHCenter
Repeater {
model: [
0, 0, 1, 0, 0,
0, 0, 0, 1, 0,
1, 1, 1, 1, 1,
0, 0, 0, 1, 0,
0, 0, 1, 0, 0
]
Rectangle {
width: 6
height: 6
radius: 2
color: "white"
opacity: modelData ? 0.9 : 0.1
}
}
}
Text {
text: "Port Forwarding"
color: "white"
font.pixelSize: 16
font.bold: true
Layout.alignment: Qt.AlignHCenter
}
Text {
text: "Manual TCP port\nconfiguration on\nyour router."
color: Qt.rgba(1, 1, 1, 0.55)
font.pixelSize: 12
horizontalAlignment: Text.AlignHCenter
Layout.alignment: Qt.AlignHCenter
Layout.preferredWidth: 150
wrapMode: Text.WordWrap
}
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: root.selectedMode = 1
}
}
}
Item {
height: Theme.spacing.small
}
RowLayout {
Layout.alignment: Qt.AlignHCenter
spacing: Theme.spacing.medium
Layout.alignment: Qt.AlignCenter
LogosStorageButton {
text: "No / I don't know"
onClicked: root.completed(false)
text: "Back"
onClicked: root.back()
}
LogosStorageButton {
text: "Yes, I use UPnP"
onClicked: function () {
console.info("enableUpnpConfig")
root.backend.enableUpnpConfig()
root.completed(true)
text: "Continue"
enabled: root.selectedMode !== -1
onClicked: {
if (root.selectedMode === 0) {
root.backend.enableUpnpConfig()
}
root.completed(root.selectedMode === 0)
}
}
}

View File

@ -53,6 +53,8 @@ LogosStorageLayout {
return backend.status == running
}
Component.onCompleted: root.backend.start()
QtObject {
id: mockBackend