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) {
QStringList importPaths = engine->importPathList();
const auto importPaths = engine->importPathList();
for (const auto &path : importPaths) {
QString fullPath = path + "/" + relativeFilePath;
const auto fullPath = path + QStringLiteral("/") + relativeFilePath;
QFile file(fullPath);
if (file.exists()) {
return fullPath;
}
}
return "";
return {};
}
QString StringUtilsInternal::readTextFile(const QString& filePath) const
@ -36,18 +36,27 @@ QString StringUtilsInternal::readTextFile(const QString& filePath) const
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)) {
auto fileUrl = resolveFileUsingQmlImportPaths(m_engine, filePath);
if (fileUrl.isEmpty()) {
const auto resolvedFilePath = resolveFileUsingQmlImportPaths(m_engine, filePath);
if (resolvedFilePath.isEmpty()) {
qWarning() << Q_FUNC_INFO << "Can't find file in QML import paths" << filePath;
return {};
}
file.setFileName(fileUrl);
file.setFileName(resolvedFilePath);
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 {};
}
}

View File

@ -6,6 +6,7 @@ import QtQml.Models 2.14
import utils 1.0
import StatusQ.Core 0.1
import StatusQ.Core.Utils 0.1 as SQUtils
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import StatusQ.Popups.Dialog 0.1
@ -13,7 +14,7 @@ import StatusQ.Popups.Dialog 0.1
StatusDialog {
id: root
width: 480
width: 600
topPadding: Style.current.bigPadding
bottomPadding: Style.current.bigPadding
closePolicy: Popup.NoAutoClose
@ -28,96 +29,94 @@ StatusDialog {
StatusButton {
objectName: "getStartedStatusButton"
enabled: acknowledge.checked && termsOfUse.checked
size: StatusBaseButton.Size.Large
font.weight: Font.Medium
text: qsTr("Get Started")
text: qsTr("Get started")
onClicked: root.close()
}
}
}
contentItem: Item {
Column {
width: 416
spacing: Style.current.padding
anchors.centerIn: parent
contentItem: ColumnLayout {
spacing: Style.current.padding
StatusCheckBox {
id: acknowledge
objectName: "acknowledgeCheckBox"
spacing: Style.current.halfPadding
font.pixelSize: 15
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.")
}
StatusCheckBox {
Layout.fillWidth: true
id: acknowledge
objectName: "acknowledgeCheckBox"
spacing: Style.current.halfPadding
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 {
id: termsOfUse
objectName: "termsOfUseCheckBox"
width: parent.width
font.pixelSize: 15
StatusCheckBox {
Layout.fillWidth: true
id: termsOfUse
objectName: "termsOfUseCheckBox"
contentItem: Row {
spacing: 4
leftPadding: termsOfUse.indicator.width + termsOfUse.spacing
contentItem: Row {
spacing: 4
leftPadding: termsOfUse.indicator.width + termsOfUse.spacing
StatusBaseText {
text: qsTr("I accept Status")
font.pixelSize: 15
StatusBaseText {
text: qsTr("I accept Status")
}
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 {
objectName: "termsOfUseLink"
text: qsTr("Terms of Use")
color: Theme.palette.primaryColor1
font.pixelSize: 15
font.weight: Font.Medium
StatusBaseText {
text: "&"
}
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/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/")
}
}
StatusLinkText {
objectName: "privacyPolicyLink"
text: qsTr("Privacy Policy")
color: Theme.palette.primaryColor1
font.weight: Font.Medium
font.pixelSize: Theme.primaryTextFontSize
onClicked: {
detailsPopup.title = qsTr("Status Software Privacy Statement")
detailsPopup.textFile = SQUtils.StringUtils.readTextFile(Qt.resolvedUrl("../../../../imports/assets/docs/privacy.mdwn"))
detailsPopup.open()
}
}
}
}
}
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