From 46e01afa04e1237cfe8861c11bda1897f7f0dc72 Mon Sep 17 00:00:00 2001 From: Patryk Osmaczko Date: Wed, 10 Aug 2022 10:27:45 +0200 Subject: [PATCH] feat(settings/profile): add social links' ui primitives iterates: #6797 --- .../controls/CustomSocialLinkInput.qml | 91 +++++++++++++ .../controls/StaticSocialLinkInput.qml | 35 +++++ .../panels/ProfileDescriptionPanel.qml | 76 +++++++++++ .../shared/controls/SocialLinkPreview.qml | 95 ++++++++++++++ ui/imports/shared/controls/qmldir | 1 + .../shared/panels/ProfileBioSocialsPanel.qml | 124 ++++++++++++++++++ ui/imports/shared/panels/qmldir | 1 + ui/imports/utils/Constants.qml | 10 ++ 8 files changed, 433 insertions(+) create mode 100644 ui/app/AppLayouts/Profile/controls/CustomSocialLinkInput.qml create mode 100644 ui/app/AppLayouts/Profile/controls/StaticSocialLinkInput.qml create mode 100644 ui/app/AppLayouts/Profile/panels/ProfileDescriptionPanel.qml create mode 100644 ui/imports/shared/controls/SocialLinkPreview.qml create mode 100644 ui/imports/shared/panels/ProfileBioSocialsPanel.qml diff --git a/ui/app/AppLayouts/Profile/controls/CustomSocialLinkInput.qml b/ui/app/AppLayouts/Profile/controls/CustomSocialLinkInput.qml new file mode 100644 index 0000000000..7fa66fd540 --- /dev/null +++ b/ui/app/AppLayouts/Profile/controls/CustomSocialLinkInput.qml @@ -0,0 +1,91 @@ +import QtQuick 2.14 +import QtQuick.Layouts 1.14 + +import utils 1.0 + +import StatusQ.Core 0.1 +import StatusQ.Core.Theme 0.1 +import StatusQ.Controls 0.1 + +import shared.controls 1.0 + +Item { + id: root + + property alias hyperlink: hyperlinkInput.text + property alias url: urlInput.text + readonly property alias removeButton: removeButton + + implicitHeight: layout.implicitHeight + implicitWidth: layout.implicitWidth + + RowLayout { + id: layout + + anchors.fill: parent + + ColumnLayout { + id: leftLayout + + spacing: 26 + + StatusInput { + id: hyperlinkInput + + Layout.fillWidth: true + label: qsTr("Hyperlink Text") + placeholderText: qsTr("Example: My Myspace Profile") + charLimit: 24 + } + + StatusInput { + id: urlInput + + Layout.fillWidth: true + label: qsTr("URL") + placeholderText: qsTr("Link URL") + } + } + + Item { + Layout.preferredWidth: 280 + Layout.fillHeight: true + + clip: true + + ColumnLayout { + x: 64 + + anchors.verticalCenter: parent.verticalCenter + + spacing: 10 + + StatusBaseText { + text: qsTr("Preview") + color: Theme.palette.baseColor1 + font.pixelSize: 15 + } + + SocialLinkPreview { + text: !!hyperlinkInput.text ? hyperlinkInput.text : qsTr("My Myspace Profile") + url: !!urlInput.text ? urlInput.text : urlInput.placeholderText + linkType: Constants.socialLinkType.custom + } + } + } + } + + + StatusFlatButton { + id: removeButton + + anchors { + right: parent.right + top: parent.top + } + + icon.name: "delete" + text: qsTr("Remove") + size: StatusBaseButton.Small + } +} diff --git a/ui/app/AppLayouts/Profile/controls/StaticSocialLinkInput.qml b/ui/app/AppLayouts/Profile/controls/StaticSocialLinkInput.qml new file mode 100644 index 0000000000..8c6c8f6051 --- /dev/null +++ b/ui/app/AppLayouts/Profile/controls/StaticSocialLinkInput.qml @@ -0,0 +1,35 @@ +import QtQuick 2.14 + +import utils 1.0 + +import StatusQ.Core 0.1 +import StatusQ.Controls 0.1 + +StatusInput { + id: root + + property int linkType + + placeholderText: { + if (linkType === Constants.socialLinkType.twitter) return qsTr("Twitter Handle") + if (linkType === Constants.socialLinkType.personalSite) return qsTr("Personal Site") + if (linkType === Constants.socialLinkType.github) return qsTr("Github") + if (linkType === Constants.socialLinkType.youtube) return qsTr("YouTube Channel") + if (linkType === Constants.socialLinkType.discord) return qsTr("Discord Handle") + if (linkType === Constants.socialLinkType.telegram) return qsTr("Telegram Handle") + return "" + } + input.icon { + name: { + if (linkType === Constants.socialLinkType.twitter) return "twitter" + if (linkType === Constants.socialLinkType.personalSite) return "language" + if (linkType === Constants.socialLinkType.github) return "github" + if (linkType === Constants.socialLinkType.youtube) return "youtube" + if (linkType === Constants.socialLinkType.discord) return "discord" + if (linkType === Constants.socialLinkType.telegram) return "telegram" + return "" + } + width: 20 + height: 20 + } +} diff --git a/ui/app/AppLayouts/Profile/panels/ProfileDescriptionPanel.qml b/ui/app/AppLayouts/Profile/panels/ProfileDescriptionPanel.qml new file mode 100644 index 0000000000..32cef522f8 --- /dev/null +++ b/ui/app/AppLayouts/Profile/panels/ProfileDescriptionPanel.qml @@ -0,0 +1,76 @@ +import QtQuick 2.14 +import QtQuick.Layouts 1.14 + +import StatusQ.Core 0.1 +import StatusQ.Core.Theme 0.1 +import StatusQ.Controls 0.1 +import StatusQ.Controls.Validators 0.1 + +import utils 1.0 +import "../controls" + +Item { + id: root + + property alias displayName: displayNameInput + property alias bio: bioInput + + property var socialLinksModel + + signal socialLinkChanged(string uuid, string text, string url) + signal addSocialLinksClicked + + implicitHeight: layout.implicitHeight + implicitWidth: layout.implicitWidth + + ColumnLayout { + id: layout + anchors.fill: parent + + spacing: 19 // by design + + StatusInput { + id: displayNameInput + + Layout.fillWidth: true + + label: qsTr("Display name") + placeholderText: qsTr("Display Name") + charLimit: 24 + validators: Constants.validators.displayName + } + + + StatusInput { + id: bioInput + + Layout.fillWidth: true + Layout.topMargin: 5 // by design + + label: qsTr("Bio") + placeholderText: qsTr("Tell us about yourself") + charLimit: 240 + multiline: true + minimumHeight: 108 + maximumHeight: 108 + input.verticalAlignment: TextEdit.AlignTop + } + + Repeater { + model: root.socialLinksModel + delegate: StaticSocialLinkInput { + Layout.fillWidth: true + linkType: model.linkType + text: model.url + + onTextChanged: root.socialLinkChanged(model.uuid, model.text, text) + } + } + + StatusIconTextButton { + Layout.topMargin: -8 // by design + text: qsTr("Add more social links") + onClicked: root.addSocialLinksClicked() + } + } +} diff --git a/ui/imports/shared/controls/SocialLinkPreview.qml b/ui/imports/shared/controls/SocialLinkPreview.qml new file mode 100644 index 0000000000..36b9b3c74c --- /dev/null +++ b/ui/imports/shared/controls/SocialLinkPreview.qml @@ -0,0 +1,95 @@ +import QtQuick 2.14 +import QtQuick.Layouts 1.14 + +import utils 1.0 + +import StatusQ.Core 0.1 +import StatusQ.Core.Theme 0.1 +import StatusQ.Controls 0.1 + +Rectangle { + id: root + + property string text + property string url + property int linkType: 1 + + implicitWidth: layout.implicitWidth + 16 + implicitHeight: layout.implicitHeight + 10 + + color: "transparent" + border { + width: 1 + color: Theme.palette.baseColor2 + } + radius: height/2 + + RowLayout { + id: layout + + anchors.centerIn: parent + + StatusIcon { + Layout.preferredWidth: 20 + Layout.preferredHeight: 20 + icon: { + if (root.linkType === Constants.socialLinkType.twitter) return "twitter" + if (root.linkType === Constants.socialLinkType.personalSite) return "language" + if (root.linkType === Constants.socialLinkType.github) return "github" + if (root.linkType === Constants.socialLinkType.youtube) return "youtube" + if (root.linkType === Constants.socialLinkType.discord) return "discord" + if (root.linkType === Constants.socialLinkType.telegram) return "telegram" + return "" + } + visible: icon !== "" + color: Theme.palette.directColor1 + } + + StatusBaseText { + text: root.linkType === Constants.socialLinkType.custom ? root.text : root.url + color: Theme.palette.directColor4 + font.weight: Font.Medium + } + } + + StatusToolTip { + id: toolTip + + contentItem: RowLayout { + StatusBaseText { + Layout.fillHeight: true + Layout.bottomMargin: 8 + + text: toolTip.text + color: Theme.palette.white + wrapMode: Text.WordWrap + font.pixelSize: 13 + font.weight: Font.Medium + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + + StatusFlatRoundButton { + Layout.preferredHeight: 24 + Layout.preferredWidth: 24 + Layout.bottomMargin: 8 + icon.name: "copy" + icon.width: 18 + icon.height: 18 + type: StatusFlatRoundButton.Tertiary + + onClicked: { + globalUtils.copyToClipboard(toolTip.text) + toolTip.visible = false + } + } + } + } + + MouseArea { + anchors.fill: parent + onClicked: toolTip.show(root.url, -1) + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + } +} diff --git a/ui/imports/shared/controls/qmldir b/ui/imports/shared/controls/qmldir index d072e1ec67..fd0b991b7e 100644 --- a/ui/imports/shared/controls/qmldir +++ b/ui/imports/shared/controls/qmldir @@ -25,3 +25,4 @@ TransactionDelegate 1.0 TransactionDelegate.qml TransactionFormGroup 1.0 TransactionFormGroup.qml EmojiHash 1.0 EmojiHash.qml InformationTile 1.0 InformationTile.qml +SocialLinkPreview 1.0 SocialLinkPreview.qml diff --git a/ui/imports/shared/panels/ProfileBioSocialsPanel.qml b/ui/imports/shared/panels/ProfileBioSocialsPanel.qml new file mode 100644 index 0000000000..3bb66945c3 --- /dev/null +++ b/ui/imports/shared/panels/ProfileBioSocialsPanel.qml @@ -0,0 +1,124 @@ +import QtQuick 2.14 +import QtQuick.Layouts 1.14 +import QtQml.Models 2.14 + +import utils 1.0 + +import StatusQ.Core 0.1 + +import "../controls" + +import SortFilterProxyModel 0.2 + +Item { + id: root + + property string bio + property string userSocialLinksJson + + onUserSocialLinksJsonChanged: d.buildSocialLinksModel() + + implicitWidth: layout.implicitWidth + implicitHeight: layout.implicitHeight + + QtObject { + id: d + + function textToType(text) { + if (text === "__twitter") return Constants.socialLinkType.twitter + if (text === "__personal_site") return Constants.socialLinkType.personalSite + if (text === "__github") return Constants.socialLinkType.github + if (text === "__youtube") return Constants.socialLinkType.youtube + if (text === "__discord") return Constants.socialLinkType.discord + if (text === "__telegram") return Constants.socialLinkType.telegram + return Constants.socialLinkType.custom + } + + // Unfortunately, nim can't expose temporary QObjects thorugh slots + // The only way to expose static models on demand is through json strings (see getContactDetailsAsJson) + // Model is built here manually, which I know is completely wrong.. + function buildSocialLinksModel() { + socialLinksModel.clear() + + if (root.userSocialLinksJson == "") return + + try { + let links = JSON.parse(root.userSocialLinksJson) + for (let i=0; i 0 + + Repeater { + id: repeater + + model: sortedSocialLinksModel + delegate: SocialLinkPreview { + text: model.text + url: model.url + linkType: model.linkType + } + } + } + } +} diff --git a/ui/imports/shared/panels/qmldir b/ui/imports/shared/panels/qmldir index 271ee1b746..96521389e8 100644 --- a/ui/imports/shared/panels/qmldir +++ b/ui/imports/shared/panels/qmldir @@ -8,6 +8,7 @@ ImageLoader 1.0 ImageLoader.qml LabelValueRow 1.0 LabelValueRow.qml ModuleWarning 1.0 ModuleWarning.qml NotificationWindow 1.0 NotificationWindow.qml +ProfileBioSocialsPanel 1.0 ProfileBioSocialsPanel.qml RoundedIcon 1.0 RoundedIcon.qml RoundedImage 1.0 RoundedImage.qml Separator 1.0 Separator.qml diff --git a/ui/imports/utils/Constants.qml b/ui/imports/utils/Constants.qml index 309f20842f..9173551c2b 100644 --- a/ui/imports/utils/Constants.qml +++ b/ui/imports/utils/Constants.qml @@ -345,6 +345,16 @@ QtObject { } } + readonly property QtObject socialLinkType: QtObject { + readonly property int custom: 0 + readonly property int twitter: 1 + readonly property int personalSite: 2 + readonly property int github: 3 + readonly property int youtube: 4 + readonly property int discord: 5 + readonly property int telegram: 6 + } + readonly property int communityImported: 0 readonly property int communityImportingInProgress: 1 readonly property int communityImportingError: 2