feat(ProfileShowcase): Create dirty state component for the web tab and integrate the UI

This commit is contained in:
Alex Jbanca 2024-03-08 11:27:45 +02:00 committed by Alex Jbanca
parent 282c4e56cd
commit 4ef30a91a3
11 changed files with 504 additions and 263 deletions

View File

@ -24,6 +24,18 @@ ColumnLayout {
ListElement { address: "4"; name: "Other Stuff" }
}
ListModel {
id: socialLinksModel
ListElement { uuid: "1"; text: "Twitter"; url: "https://twitter.com/status" }
ListElement { uuid: "2"; text: "Personal Site"; url: "https://status.im" }
ListElement { uuid: "3"; text: "Github"; url: "https://github.com" }
ListElement { uuid: "4"; text: "Youtube"; url: "https://youtube.com" }
ListElement { uuid: "5"; text: "Discord"; url: "https://discord.com" }
ListElement { uuid: "6"; text: "Telegram"; url: "https://t.me/status" }
ListElement { uuid: "7"; text: "Custom"; url: "https://status.im" }
}
ListModel {
id: accountsShowcaseModel
ListElement {
@ -173,6 +185,8 @@ ColumnLayout {
collectiblesSourceModel: collectiblesModel
collectiblesShowcaseModel: collectiblesShowcaseModel
socialLinksSourceModel: socialLinksModel
}
ListModel {
@ -199,208 +213,277 @@ ColumnLayout {
valueRole: "value"
}
Flickable {
StackView {
id: stackView
Layout.fillWidth: true
Layout.fillHeight: true
Layout.margins: 10
contentWidth: grid.width
contentHeight: grid.height
initialItem: collectiblesView
Component {
id: collectiblesView
Flickable {
clip: true
contentWidth: grid.width
contentHeight: grid.height
Grid {
id: grid
clip: true
rows: 3
columns: 4
Grid {
id: grid
spacing: 10
rows: 3
columns: 4
flow: Grid.TopToBottom
spacing: 10
Label {
text: "Backend models"
font.pixelSize: 22
padding: 10
}
flow: Grid.TopToBottom
GenericListView {
width: 300
height: 300
model: accountsModel
label: "ACCOUNTS MODEL"
}
GenericListView {
width: 300
height: 300
model: accountsShowcaseModel
label: "SHOWCASE MODEL"
roles: ["showcaseKey", "showcaseVisibility", "showcasePosition"]
}
Label {
text: "Display models"
font.pixelSize: 22
padding: 10
}
GenericListView {
width: 420
height: 300
model: showcaseModels.accountsVisibleModel
label: "IN SHOWCASE"
movable: true
roles: ["showcaseKey", "showcaseVisibility", "showcasePosition"]
onMoveRequested: {
showcaseModels.changeAccountPosition(from, to);
}
insetComponent: RowLayout {
readonly property var topModel: model
RoundButton {
text: "❌"
onClicked: showcaseModels.setAccountVisibility(
model.showcaseKey,
Constants.ShowcaseVisibility.NoOne)
Label {
text: "Backend models"
font.pixelSize: 22
padding: 10
}
VisibilityComboBox {
property bool completed: false
GenericListView {
width: 300
height: 300
onCurrentValueChanged: {
if (!completed || topModel.index < 0)
return
model: accountsModel
label: "ACCOUNTS MODEL"
}
showcaseModels.setAccountVisibility(
topModel.showcaseKey, currentValue)
GenericListView {
width: 300
height: 300
model: accountsShowcaseModel
label: "SHOWCASE MODEL"
roles: ["showcaseKey", "showcaseVisibility", "showcasePosition"]
}
Label {
text: "Display models"
font.pixelSize: 22
padding: 10
}
GenericListView {
width: 420
height: 300
model: showcaseModels.accountsVisibleModel
label: "IN SHOWCASE"
movable: true
roles: ["showcaseKey", "showcaseVisibility", "showcasePosition"]
onMoveRequested: {
showcaseModels.changeAccountPosition(from, to);
}
Component.onCompleted: {
currentIndex = indexOfValue(topModel.showcaseVisibility)
completed = true
insetComponent: RowLayout {
readonly property var topModel: model
RoundButton {
text: "❌"
onClicked: showcaseModels.setAccountVisibility(
model.showcaseKey,
Constants.ShowcaseVisibility.NoOne)
}
VisibilityComboBox {
property bool completed: false
onCurrentValueChanged: {
if (!completed || topModel.index < 0)
return
showcaseModels.setAccountVisibility(
topModel.showcaseKey, currentValue)
}
Component.onCompleted: {
currentIndex = indexOfValue(topModel.showcaseVisibility)
completed = true
}
}
}
}
GenericListView {
width: 420
height: 300
model: showcaseModels.accountsHiddenModel
label: "HIDDEN"
roles: ["showcaseKey", "showcaseVisibility", "showcasePosition"]
insetComponent: Button {
text: "unhide"
onClicked:
showcaseModels.setAccountVisibility(
model.showcaseKey,
Constants.ShowcaseVisibility.IdVerifiedContacts)
}
}
Label {
text: "Backend models"
font.pixelSize: 22
padding: 10
}
GenericListView {
width: 270
height: 300
model: collectiblesModel
label: "COLLECTIBLES MODEL"
}
GenericListView {
width: 270
height: 300
model: collectiblesShowcaseModel
label: "SHOWCASE MODEL"
roles: ["uid", "showcaseVisibility", "order"]
}
Label {
text: "Display models"
font.pixelSize: 22
padding: 10
}
GenericListView {
width: 610
height: 300
model: showcaseModels.collectiblesVisibleModel
label: "IN SHOWCASE"
movable: true
roles: ["showcaseKey", "showcaseVisibility", "showcasePosition"]
onMoveRequested: {
showcaseModels.changeCollectiblePosition(from, to);
}
insetComponent: RowLayout {
readonly property var topModel: model
RoundButton {
text: "❌"
onClicked: showcaseModels.setCollectibleVisibility(
model.showcaseKey,
Constants.ShowcaseVisibility.NoOne)
}
VisibilityComboBox {
property bool completed: false
onCurrentValueChanged: {
if (!completed || topModel.index < 0)
return
showcaseModels.setCollectibleVisibility(
topModel.showcaseKey, currentValue)
}
Component.onCompleted: {
currentIndex = indexOfValue(topModel.showcaseVisibility)
completed = true
}
}
}
}
GenericListView {
width: 610
height: 300
model: showcaseModels.collectiblesHiddenModel
label: "HIDDEN"
roles: ["showcaseKey", "showcaseVisibility", "showcasePosition",
"accounts", "maxVisibility"]
insetComponent: Button {
text: "unhide"
onClicked:
showcaseModels.setCollectibleVisibility(
model.showcaseKey,
Constants.ShowcaseVisibility.IdVerifiedContacts)
}
}
}
}
}
Component {
id: webView
Flickable {
GenericListView {
width: 420
height: 300
contentWidth: webGrid.implicitWidth
contentHeight: webGrid.implicitHeight
model: showcaseModels.accountsHiddenModel
Grid {
id: webGrid
label: "HIDDEN"
rows: 3
columns: 4
roles: ["showcaseKey", "showcaseVisibility", "showcasePosition"]
spacing: 10
insetComponent: Button {
text: "unhide"
flow: Grid.TopToBottom
onClicked:
showcaseModels.setAccountVisibility(
model.showcaseKey,
Constants.ShowcaseVisibility.IdVerifiedContacts)
}
}
Label {
text: "Backend models"
font.pixelSize: 22
padding: 10
}
GenericListView {
width: 270
height: 300
model: collectiblesModel
label: "COLLECTIBLES MODEL"
}
GenericListView {
width: 270
height: 300
model: collectiblesShowcaseModel
label: "SHOWCASE MODEL"
roles: ["uid", "showcaseVisibility", "order"]
}
Label {
text: "Display models"
font.pixelSize: 22
padding: 10
}
GenericListView {
width: 610
height: 300
model: showcaseModels.collectiblesVisibleModel
label: "IN SHOWCASE"
movable: true
roles: ["showcaseKey", "showcaseVisibility", "showcasePosition"]
onMoveRequested: {
showcaseModels.changeCollectiblePosition(from, to);
}
insetComponent: RowLayout {
readonly property var topModel: model
RoundButton {
text: "❌"
onClicked: showcaseModels.setCollectibleVisibility(
model.showcaseKey,
Constants.ShowcaseVisibility.NoOne)
Label {
text: "Backend models"
font.pixelSize: 22
padding: 10
}
VisibilityComboBox {
property bool completed: false
GenericListView {
width: 300
height: 300
onCurrentValueChanged: {
if (!completed || topModel.index < 0)
return
model: socialLinksModel
label: "SOCIAL LINKS MODEL"
}
showcaseModels.setCollectibleVisibility(
topModel.showcaseKey, currentValue)
}
Item {
Component.onCompleted: {
currentIndex = indexOfValue(topModel.showcaseVisibility)
completed = true
width: 300
height: 300
}
Label {
text: "Display models"
font.pixelSize: 22
padding: 10
}
GenericListView {
width: 610
height: 300
model: showcaseModels.socialLinksVisibleModel
label: "IN SHOWCASE"
movable: true
onMoveRequested: {
showcaseModels.changeSocialLinkPosition(from, to);
}
}
}
}
GenericListView {
width: 610
height: 300
model: showcaseModels.collectiblesHiddenModel
label: "HIDDEN"
roles: ["showcaseKey", "showcaseVisibility", "showcasePosition",
"accounts", "maxVisibility"]
insetComponent: Button {
text: "unhide"
onClicked:
showcaseModels.setCollectibleVisibility(
model.showcaseKey,
Constants.ShowcaseVisibility.IdVerifiedContacts)
}
}
}
}
@ -417,6 +500,28 @@ ColumnLayout {
Layout.alignment: Qt.AlignHCenter
}
RowLayout {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.alignment: Qt.AlignHCenter
Button {
text: "Collectibles tab"
onClicked: {
stackView.replace(webView, collectiblesView)
}
}
Button {
text: "Web tab"
onClicked: {
stackView.replace(collectiblesView, webView)
}
}
}
Button {
text: "SAVE"
//TODO: enable when showcaseModels backend APIs is integrated

View File

@ -25,56 +25,46 @@ SplitView {
communityTokensStore: CommunityTokensStore {}
}
ListModel {
id: emptyModel
}
ListModel {
id: linksModel
ListElement {
uuid: "0001"
text: "__github"
url: "https://github.com/caybro"
linkType: 3 // Constants.socialLinkType.github
icon: "github"
}
ListElement {
uuid: "0002"
text: "__twitter"
url: "https://twitter.com/caybro"
linkType: 1 // Constants.socialLinkType.twitter
icon: "twitter"
}
ListElement {
uuid: "0003"
text: "__personal_site"
url: "https://status.im"
linkType: 2 // Constants.socialLinkType.personalSite
icon: "language"
}
ListElement {
uuid: "0004"
text: "__youtube"
url: "https://www.youtube.com/@LukasTinkl"
linkType: 4 // Constants.socialLinkType.youtube
icon: "youtube"
}
ListElement { // NB: empty on purpose, for testing
uuid: ""
text: ""
url: ""
linkType: -1
icon: ""
}
ListElement {
uuid: "0005"
text: "Figma design very long URL link text that should elide"
url: "https://www.figma.com/file/idUoxN7OIW2Jpp3PMJ1Rl8/%E2%9A%99%EF%B8%8F-Settings-%7C-Desktop?node-id=1223%3A124882&t=qvYeJ8grsZLyUS0V-0"
linkType: 0 // Constants.socialLinkType.custom
icon: "link"
}
ListElement {
uuid: "0006"
text: "__telegram"
url: "https://t.me/ltinkl"
linkType: 6 // Constants.socialLinkType.telegram
icon: "telegram"
}
}
@ -89,47 +79,31 @@ SplitView {
SplitView.fillWidth: true
SplitView.preferredHeight: 300
ProfileSocialLinksPanel {
id: socialLinksPanel
property var linksModel: emptyModelCheck.checked ? emptyModel : linksModel
width: 500
profileStore: QtObject {
function createLink(text, url, linkType, icon) {
logs.logEvent("ProfileStore::createLink", ["text", "url", "linkType", "icon"], arguments)
linksModel.append({text, url, linkType, icon})
}
function removeLink(uuid) {
logs.logEvent("ProfileStore::removeLink", ["uuid"], arguments)
const idx = CoreUtils.ModelUtils.indexOf(linksModel, "uuid", uuid)
if (idx === -1)
return
linksModel.remove(idx, 1)
}
function updateLink(uuid, text, url) {
logs.logEvent("ProfileStore::updateLink", ["uuid", "text", "url"], arguments)
const idx = CoreUtils.ModelUtils.indexOf(linksModel, "uuid", uuid)
if (idx === -1)
return
if (!!text)
linksModel.setProperty(idx, "text", text)
if (!!url)
linksModel.setProperty(idx, "url", url)
}
function moveLink(fromRow, toRow, count) {
logs.logEvent("ProfileStore::moveLink", ["fromRow", "toRow", "count"], arguments)
linksModel.move(fromRow, toRow, 1)
}
function resetSocialLinks() {
logs.logEvent("ProfileStore::resetSocialLinks")
}
function saveSocialLinks(silent = false) {
logs.logEvent("ProfileStore::saveSocialLinks", ["silent"], arguments)
}
onAddSocialLink: {
logs.logEvent("ProfileSocialLinksPanel::addSocialLink", ["url", "text"], arguments)
socialLinksPanel.linksModel.append({text: text, url: url})
}
onUpdateSocialLink: {
logs.logEvent("ProfileSocialLinksPanel::updateSocialLink", ["index", "url", "text"], arguments)
if (!!text)
socialLinksPanel.linksModel.setProperty(index, "text", text)
if (!!url)
socialLinksPanel.linksModel.setProperty(index, "url", url)
}
onRemoveSocialLink: {
logs.logEvent("ProfileSocialLinksPanel::removeSocialLink", ["index"], arguments)
socialLinksPanel.linksModel.remove(index, 1)
}
onChangePosition: {
logs.logEvent("ProfileSocialLinksPanel::changePosition", ["from", "to"], arguments)
socialLinksPanel.linksModel.move(from, to, 1)
}
socialLinksModel: linksModel
socialLinksModel: socialLinksPanel.linksModel
}
}
@ -140,6 +114,13 @@ SplitView {
SplitView.preferredHeight: 200
logsView.logText: logs.logText
CheckBox {
id: emptyModelCheck
text: "emptyModel"
checked: false
}
}
}

View File

@ -122,17 +122,22 @@ Item {
property bool isInputValidWord: false
}
StatusInput {
id: seedWordInput
implicitWidth: parent.width
input.leftComponent: StatusBaseText {
Component {
id: seedInputLeftComponent
StatusBaseText {
rightPadding: 6
text: root.leftComponentText
color: seedWordInput.input.edit.activeFocus ?
Theme.palette.primaryColor1 : Theme.palette.baseColor1
font.pixelSize: 15
}
}
StatusInput {
id: seedWordInput
implicitWidth: parent.width
input.leftComponent: seedInputLeftComponent
input.acceptReturn: true
onTextChanged: {
d.isInputValidWord = false

View File

@ -21,6 +21,13 @@ QObject {
property alias sourceModel: joined.leftModel
property alias showcaseModel: joined.rightModel
/**
* True if the showcase model is in single model mode, i.e. the showcase
* model is part of the source model. False if the showcase model is a
* separate model.
*/
property bool singleModelMode: !joined.rightModel
/**
* Model holding elements from 'sourceModel' intended to be visible in the
* showcase, sorted by 'position' role. Includes roles from both input models.
@ -48,8 +55,8 @@ QObject {
writable.revert()
}
function currentState() {
return writable.currentState()
function currentState(roleNames = []) {
return writable.currentState(roleNames)
}
function setVisibility(key, visibility) {
@ -67,11 +74,25 @@ QObject {
writableIndexes.push(visibleSFPM.mapToSource(newOrder[i]))
}
for (var j = 0; j < newOrder.length; j++) {
writable.set(writableIndexes[j], { "showcasePosition": j})
for (var i = 0; i < newOrder.length; i++) {
writable.set(writableIndexes[i], { "showcasePosition": i})
}
}
function append(obj) {
writable.append(obj)
}
function remove(index) {
const writableIndex = d.visibleIndexToWritable(index)
writable.remove(writableIndex)
}
function update(index, obj) {
const writableIndex = d.visibleIndexToWritable(index)
writable.set(writableIndex, obj)
}
// internals, debug purpose only
readonly property alias writable_: writable
readonly property alias joined_: joined
@ -96,7 +117,7 @@ QObject {
VisibilityAndPositionDirtyStateModel {
id: writable
sourceModel: joined
sourceModel: root.singleModelMode ? root.sourceModel : joined
visibilityHidden: Constants.ShowcaseVisibility.NoOne
}
@ -140,4 +161,15 @@ QObject {
filters: HiddenFilter {}
}
QtObject {
id: d
function visibleIndexToWritable(index) {
const newOrder = visible.order()
const sfpmIndex = newOrder[index]
return visibleSFPM.mapToSource(sfpmIndex)
}
}
}

View File

@ -1,10 +1,13 @@
import QtQml 2.15
import QtQml.Models 2.15
import StatusQ 0.1
import StatusQ.Core.Utils 0.1
import SortFilterProxyModel 0.2
import utils 1.0
QObject {
id: root
@ -32,6 +35,11 @@ QObject {
readonly property alias adaptedCollectiblesSourceModel: collectiblesSFPM
readonly property alias adaptedCollectiblesShowcaseModel: collectiblesRenamingShowcase
// Social links input models
property alias socialLinksSourceModel: socialLinksRoleRenaming.sourceModel
// adapted models
readonly property alias adaptedSocialLinksSourceModel: socialLinksSFPM
SortFilterProxyModel {
id: communitySFPM
@ -192,4 +200,32 @@ QObject {
}
]
}
}
RolesRenamingModel {
id: socialLinksRoleRenaming
mapping: [
RoleRename {
from: "uuid"
to: "showcaseKey"
}
]
}
SortFilterProxyModel {
id: socialLinksSFPM
sourceModel: socialLinksRoleRenaming
proxyRoles: [
FastExpressionRole {
name: "showcasePosition"
expression: index
},
FastExpressionRole {
name: "showcaseVisibility"
expression: getShowcaseVisibility()
function getShowcaseVisibility() {
return Constants.ShowcaseVisibility.Everyone
}
}
]
}
}

View File

@ -11,12 +11,13 @@ QObject {
id: root
// GENERAL
readonly property bool dirty: communities.dirty || accounts.dirty || collectibles.dirty
readonly property bool dirty: communities.dirty || accounts.dirty || collectibles.dirty || socialLinks.dirty
function revert() {
communities.revert()
accounts.revert()
collectibles.revert()
socialLinks.revert()
}
// COMMUNITIES
@ -98,14 +99,43 @@ QObject {
collectibles.changePosition(from, to)
}
// SOCIAL LINKS
// Input models
property alias socialLinksSourceModel: modelAdapter.socialLinksSourceModel
// Output models
readonly property alias socialLinksVisibleModel: socialLinks.visibleModel
// Methods
function appendSocialLink(obj) {
socialLinks.append(obj)
}
function updateSocialLink(index, obj) {
socialLinks.update(index, obj)
}
function removeSocialLink(index) {
socialLinks.remove(index)
}
function changeSocialLinkPosition(from, to) {
socialLinks.changePosition(from, to)
}
function socialLinksCurrentState(roleNames) {
return socialLinks.currentState(roleNames)
}
// The complete preferences models json current state:
function buildJSONModelsCurrentState() {
return JSON.stringify({
"communities": communitiesCurrentState(),
"accounts": accountsCurrentState(),
"collectibles": collectiblesCurrentState()
"collectibles": collectiblesCurrentState(),
"socialLinks": socialLinksCurrentState(["url", "text", "showcaseVisibility", "showcasePosition"])
// TODO: Assets --> Issue #13492
// TODO: Web --> Issue #13495
})
}
@ -164,6 +194,14 @@ QObject {
}
}
ProfileShowcaseDirtyState {
id: socialLinks
sourceModel: modelAdapter.adaptedSocialLinksSourceModel
singleModelMode: true
}
SortFilterProxyModel {
id: collectiblesFilter

View File

@ -31,8 +31,8 @@ WritableProxyModel {
*
* The entries with visibility 0 (hidden) are not included in the list.
*/
function currentState() {
const visible = d.getVisibleEntries()
function currentState(roleNames) {
const visible = d.getVisibleEntries(roleNames)
const minPos = Math.min(...visible.map(e => e.showcasePosition))
return visible.map(e => { e.showcasePosition -= minPos; return e })
@ -75,9 +75,14 @@ WritableProxyModel {
return ModelUtils.indexOf(root, "showcaseKey", key)
}
function getVisibleEntries() {
const roles = ["showcaseKey", "showcasePosition", "showcaseVisibility"]
const keysAndPos = ModelUtils.modelToArray(root, roles)
function getVisibleEntries(roleNames = ["showcaseKey", "showcasePosition", "showcaseVisibility"]) {
if (roleNames.length === 0)
roleNames = ["showcaseKey", "showcasePosition", "showcaseVisibility"]
if (!roleNames.includes("showcaseVisibility"))
roleNames.push("showcaseVisibility")
const keysAndPos = ModelUtils.modelToArray(root, roleNames)
return keysAndPos.filter(p => p.showcaseVisibility
&& p.showcaseVisibility !== root.visibilityHidden)

View File

@ -3,6 +3,7 @@ import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import StatusQ.Core 0.1
import StatusQ.Core.Utils 0.1
import StatusQ.Controls 0.1
import StatusQ.Components 0.1
import StatusQ.Core.Theme 0.1
@ -17,27 +18,40 @@ import SortFilterProxyModel 0.2
Control {
id: root
property var profileStore
property var socialLinksModel
property int showcaseLimit: 20
background: null
signal addSocialLink(string url, string text)
signal updateSocialLink(int index, string url, string text)
signal removeSocialLink(int index)
signal changePosition(int from, int to)
QtObject {
id: d
function containsSocialLink(text, url) {
return ModelUtils.contains(socialLinksModel, "text", text, Qt.CaseInsensitive) &&
ModelUtils.contains(socialLinksModel, "url", url, Qt.CaseInsensitive)
}
}
Component {
id: addSocialLinkModalComponent
AddSocialLinkModal {
containsSocialLink: root.profileStore.containsSocialLink
onAddLinkRequested: root.profileStore.createLink(linkText, linkUrl, linkType, linkIcon)
containsSocialLink: d.containsSocialLink
onAddLinkRequested: root.addSocialLink(linkUrl, linkText)
}
}
Component {
id: modifySocialLinkModal
ModifySocialLinkModal {
containsSocialLink: root.profileStore.containsSocialLink
onUpdateLinkRequested: root.profileStore.updateLink(uuid, linkText, linkUrl)
onRemoveLinkRequested: root.profileStore.removeLink(uuid)
containsSocialLink: d.containsSocialLink
onUpdateLinkRequested: root.updateSocialLink(index, linkUrl, linkText)
onRemoveLinkRequested: root.removeSocialLink(index)
}
}
@ -54,7 +68,7 @@ Control {
}
Item { Layout.fillWidth: true }
StatusBaseText {
text: qsTr("%1 / %2").arg(root.profileStore.temporarySocialLinksModel.count).arg(root.showcaseLimit)
text: qsTr("%1 / %2").arg(linksView.count).arg(root.showcaseLimit)
color: Theme.palette.baseColor1
font.pixelSize: Theme.tertiaryTextFontSize
}
@ -62,7 +76,7 @@ Control {
// empty placeholder when no links; dashed rounded rectangle
ShapeRectangle {
readonly property bool maxReached: root.profileStore.temporarySocialLinksModel.count === root.showcaseLimit
readonly property bool maxReached: linksView.count === root.showcaseLimit
Layout.alignment: Qt.AlignHCenter
Layout.preferredWidth: parent.width - 4 // the rectangular path is rendered outside
@ -115,18 +129,16 @@ Control {
const to = draggableDelegate.visualIndex
if (to === from)
return
root.profileStore.moveLink(from, to, 1)
root.changePosition(from, to)
drag.accept()
}
onDropped: function(drop) {
root.profileStore.saveSocialLinks(true /*silent*/)
}
StatusDraggableListItem {
id: draggableDelegate
readonly property string asideText: ProfileUtils.stripSocialLinkPrefix(model.url, model.linkType)
readonly property string asideText: ProfileUtils.stripSocialLinkPrefix(model.url, draggableDelegate.linkType)
readonly property int linkType: ProfileUtils.linkTextToType(model.text)
readonly property string iconName: ProfileUtils.linkTypeToIcon(draggableDelegate.linkType)
visible: !!asideText
width: parent.width
@ -142,11 +154,11 @@ Control {
dragParent: linksView
visualIndex: delegateRoot.visualIndex
draggable: linksView.count > 1
title: ProfileUtils.linkTypeToShortText(model.linkType) || model.text
title: ProfileUtils.linkTypeToShortText(draggableDelegate.linkType) || model.text
hasIcon: true
icon.name: model.icon
icon.color: ProfileUtils.linkTypeColor(model.linkType)
assetBgColor: ProfileUtils.linkTypeBgColor(model.linkType)
icon.name: draggableDelegate.iconName
icon.color: ProfileUtils.linkTypeColor(draggableDelegate.linkType)
assetBgColor: ProfileUtils.linkTypeBgColor(draggableDelegate.linkType)
actions: [
StatusLinkText {
Layout.fillWidth: true
@ -167,7 +179,7 @@ Control {
type: StatusFlatRoundButton.Type.Tertiary
tooltip.text: qsTr("Edit link")
onClicked: Global.openPopup(modifySocialLinkModal,
{linkType: model.linkType, icon: model.icon, uuid: model.uuid,
{linkType: draggableDelegate.linkType, icon: draggableDelegate.iconName, index: delegateRoot.visualIndex,
linkText: model.text, linkUrl: draggableDelegate.asideText})
}
]

View File

@ -21,12 +21,12 @@ StatusDialog {
property int linkType: -1
property string icon
property string uuid
property int index
property string linkText
property string linkUrl
signal updateLinkRequested(string uuid, string linkText, string linkUrl)
signal removeLinkRequested(string uuid)
signal updateLinkRequested(string index, string linkText, string linkUrl)
signal removeLinkRequested(string index)
implicitWidth: 480 // design
@ -38,7 +38,7 @@ StatusDialog {
type: StatusButton.Danger
text: qsTr("Delete")
onClicked: {
root.removeLinkRequested(root.uuid)
root.removeLinkRequested(root.index)
root.close()
}
}
@ -48,7 +48,7 @@ StatusDialog {
text: qsTr("Update")
enabled: linkTarget.valid && (!customTitle.visible || customTitle.valid)
onClicked: {
root.updateLinkRequested(root.uuid, customTitle.text, ProfileUtils.addSocialLinkPrefix(linkTarget.text, root.linkType))
root.updateLinkRequested(root.index, customTitle.text, ProfileUtils.addSocialLinkPrefix(linkTarget.text, root.linkType))
root.close()
}
}

View File

@ -140,6 +140,8 @@ SettingsContentBase {
collectiblesSourceModel: root.profileStore.collectiblesModel
collectiblesShowcaseModel: root.profileStore.profileShowcaseCollectiblesModel
collectiblesSearcherText: profileShowcaseCollectiblesPanel.searcherText
socialLinksSourceModel: root.profileStore.socialLinksModel
}
function reset() {
@ -290,9 +292,24 @@ SettingsContentBase {
// web
ProfileSocialLinksPanel {
profileStore: root.profileStore
socialLinksModel: root.profileStore.temporarySocialLinksModel
showcaseLimit: root.profileStore.getProfileShowcaseSocialLinksLimit()
socialLinksModel: priv.showcaseModels.socialLinksVisibleModel
onAddSocialLink: function(url, text) {
priv.showcaseModels.appendSocialLink({ showcaseKey: "", text: text, url: url })
}
onUpdateSocialLink: function(index, url, text) {
priv.showcaseModels.updateSocialLink(index, { text: text, url: url })
}
onRemoveSocialLink: function(index) {
priv.showcaseModels.removeSocialLink(index)
}
onChangePosition: function(from, to) {
priv.showcaseModels.changeSocialLinkPosition(from, to)
}
}
Component {

View File

@ -78,6 +78,16 @@ QtObject {
return Constants.socialLinkType.custom
}
function linkTypeToIcon(linkType) {
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 "link"
}
// showcase
function visibilityIcon(showcaseVisibility) {
switch (showcaseVisibility) {