fix[onboarding] Broken links to "Terms" and "Privacy"

- display the locally bundled privacy/terms of use texts in a popup
- add support for reading text files with both relative and absolute
files or URLs, useful for having the same file path in both storybook
and the app

Fixes #13877
This commit is contained in:
Lukáš Tinkl 2024-03-11 15:31:28 +01:00 committed by Lukáš Tinkl
parent e7a1f5e831
commit 666ba77051
4 changed files with 149 additions and 85 deletions

View File

@ -0,0 +1,55 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtQml 2.15
import AppLayouts.Onboarding.popups 1.0
import utils 1.0
import Storybook 1.0
SplitView {
id: root
orientation: Qt.Vertical
Logs { id: logs }
function openDialog() {
popupComponent.createObject(popupBg)
}
Component.onCompleted: openDialog()
Item {
SplitView.fillWidth: true
SplitView.fillHeight: true
PopupBackground {
id: popupBg
anchors.fill: parent
Button {
anchors.centerIn: parent
text: "Reopen"
onClicked: openDialog()
}
}
}
Component {
id: popupComponent
BeforeGetStartedModal {
id: popup
anchors.centerIn: parent
modal: false
visible: true
onClosed: destroy()
}
}
}
// category: Popups
// https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba%E2%8E%9CDesktop?type=design&node-id=38555-18004&mode=design&t=WHoI8vkSC9JScbPx-0

View File

@ -17,15 +17,15 @@ QString StringUtilsInternal::escapeHtml(const QString& unsafe) const
} }
QString resolveFileUsingQmlImportPaths(QQmlEngine *engine, const QString &relativeFilePath) { QString resolveFileUsingQmlImportPaths(QQmlEngine *engine, const QString &relativeFilePath) {
QStringList importPaths = engine->importPathList(); const auto importPaths = engine->importPathList();
for (const auto &path : importPaths) { for (const auto &path : importPaths) {
QString fullPath = path + "/" + relativeFilePath; const auto fullPath = path + QStringLiteral("/") + relativeFilePath;
QFile file(fullPath); QFile file(fullPath);
if (file.exists()) { if (file.exists()) {
return fullPath; return fullPath;
} }
} }
return ""; return {};
} }
QString StringUtilsInternal::readTextFile(const QString& filePath) const QString StringUtilsInternal::readTextFile(const QString& filePath) const
@ -36,18 +36,27 @@ QString StringUtilsInternal::readTextFile(const QString& filePath) const
return {}; return {};
} }
const auto resolvedFilePath = selector->selector()->select(filePath); QString selectedFilePath;
const auto maybeFileUrl = QUrl(filePath).toLocalFile(); // support local file URLs (e.g. "file:///foo/bar/baz.txt")
QFile file(resolvedFilePath); if (QFile::exists(maybeFileUrl))
selectedFilePath = maybeFileUrl;
else
selectedFilePath = selector->selector()->select(filePath);
if (selectedFilePath.startsWith(QLatin1String("qrc:/"))) // for some reason doesn't work with the "qrc:/" prefix, drop it
selectedFilePath.remove(0, 3);
QFile file(selectedFilePath);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
auto fileUrl = resolveFileUsingQmlImportPaths(m_engine, filePath); const auto resolvedFilePath = resolveFileUsingQmlImportPaths(m_engine, filePath);
if (fileUrl.isEmpty()) { if (resolvedFilePath.isEmpty()) {
qWarning() << Q_FUNC_INFO << "Can't find file in QML import paths" << filePath; qWarning() << Q_FUNC_INFO << "Can't find file in QML import paths" << filePath;
return {}; return {};
} }
file.setFileName(fileUrl); file.setFileName(resolvedFilePath);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qWarning() << Q_FUNC_INFO << "Error opening existing file" << fileUrl << "for reading"; qWarning() << Q_FUNC_INFO << "Error opening existing file" << resolvedFilePath << "for reading";
return {}; return {};
} }
} }

View File

@ -6,6 +6,7 @@ import QtQml.Models 2.14
import utils 1.0 import utils 1.0
import StatusQ.Core 0.1 import StatusQ.Core 0.1
import StatusQ.Core.Utils 0.1 as SQUtils
import StatusQ.Core.Theme 0.1 import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1 import StatusQ.Controls 0.1
import StatusQ.Popups.Dialog 0.1 import StatusQ.Popups.Dialog 0.1
@ -13,7 +14,7 @@ import StatusQ.Popups.Dialog 0.1
StatusDialog { StatusDialog {
id: root id: root
width: 480 width: 600
topPadding: Style.current.bigPadding topPadding: Style.current.bigPadding
bottomPadding: Style.current.bigPadding bottomPadding: Style.current.bigPadding
closePolicy: Popup.NoAutoClose closePolicy: Popup.NoAutoClose
@ -28,96 +29,94 @@ StatusDialog {
StatusButton { StatusButton {
objectName: "getStartedStatusButton" objectName: "getStartedStatusButton"
enabled: acknowledge.checked && termsOfUse.checked enabled: acknowledge.checked && termsOfUse.checked
size: StatusBaseButton.Size.Large text: qsTr("Get started")
font.weight: Font.Medium
text: qsTr("Get Started")
onClicked: root.close() onClicked: root.close()
} }
} }
} }
contentItem: Item { contentItem: ColumnLayout {
Column { spacing: Style.current.padding
width: 416
spacing: Style.current.padding
anchors.centerIn: parent
StatusCheckBox { StatusCheckBox {
id: acknowledge Layout.fillWidth: true
objectName: "acknowledgeCheckBox" id: acknowledge
spacing: Style.current.halfPadding objectName: "acknowledgeCheckBox"
font.pixelSize: 15 spacing: Style.current.halfPadding
width: parent.width text: qsTr("I acknowledge that Status Desktop is in Beta and by using it I take the full responsibility for all risks concerning my data and funds.")
text: qsTr("I acknowledge that Status Desktop is in Beta and by using it I take the full responsibility for all risks concerning my data and funds.") }
}
StatusCheckBox { StatusCheckBox {
id: termsOfUse Layout.fillWidth: true
objectName: "termsOfUseCheckBox" id: termsOfUse
width: parent.width objectName: "termsOfUseCheckBox"
font.pixelSize: 15
contentItem: Row { contentItem: Row {
spacing: 4 spacing: 4
leftPadding: termsOfUse.indicator.width + termsOfUse.spacing leftPadding: termsOfUse.indicator.width + termsOfUse.spacing
StatusBaseText { StatusBaseText {
text: qsTr("I accept Status") text: qsTr("I accept Status")
font.pixelSize: 15 }
StatusLinkText {
objectName: "termsOfUseLink"
text: qsTr("Terms of Use")
color: Theme.palette.primaryColor1
font.weight: Font.Medium
font.pixelSize: Theme.primaryTextFontSize
onClicked: {
detailsPopup.title = qsTr("Status Software Terms of Use")
detailsPopup.textFile = SQUtils.StringUtils.readTextFile(Qt.resolvedUrl("../../../../imports/assets/docs/terms-of-use.mdwn"))
detailsPopup.open()
} }
}
StatusBaseText { StatusBaseText {
objectName: "termsOfUseLink" text: "&"
text: qsTr("Terms of Use") }
color: Theme.palette.primaryColor1
font.pixelSize: 15
font.weight: Font.Medium
MouseArea { StatusLinkText {
anchors.fill: parent objectName: "privacyPolicyLink"
cursorShape: Qt.PointingHandCursor text: qsTr("Privacy Policy")
hoverEnabled: true color: Theme.palette.primaryColor1
onEntered: { font.weight: Font.Medium
parent.font.underline = true font.pixelSize: Theme.primaryTextFontSize
} onClicked: {
onExited: { detailsPopup.title = qsTr("Status Software Privacy Statement")
parent.font.underline = false detailsPopup.textFile = SQUtils.StringUtils.readTextFile(Qt.resolvedUrl("../../../../imports/assets/docs/privacy.mdwn"))
} detailsPopup.open()
onClicked: {
Qt.openUrlExternally("https://status.im/terms-of-use/")
}
}
}
StatusBaseText {
text: "&"
font.pixelSize: 15
}
StatusBaseText {
objectName: "privacyPolicyLink"
text: qsTr("Privacy Policy")
color: Theme.palette.primaryColor1
font.pixelSize: 15
font.weight: Font.Medium
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
onEntered: {
parent.font.underline = true
}
onExited: {
parent.font.underline = false
}
onClicked: {
Qt.openUrlExternally("https://status.im/privacy-policy/")
}
}
} }
} }
} }
} }
} }
StatusDialog {
id: detailsPopup
property string textFile
width: 600
padding: 0
standardButtons: Dialog.Ok
anchors.centerIn: parent
visible: false
onClosed: textFile = ""
StatusScrollView {
id: scrollView
anchors.fill: parent
contentWidth: availableWidth
padding: 20
StatusBaseText {
width: scrollView.availableWidth
wrapMode: Text.Wrap
textFormat: Text.MarkdownText
text: detailsPopup.textFile
}
}
}
} }

View File

@ -0,0 +1 @@
BeforeGetStartedModal 1.0 BeforeGetStartedModal.qml