mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-08-16 20:15:56 +08:00
Merge remote-tracking branch 'origin/marketplace_redesign' into CURA-8559_add_marketplace_search
This commit is contained in:
commit
bc0b7301e5
@ -4,10 +4,12 @@
|
|||||||
from PyQt5.QtCore import pyqtProperty, QObject
|
from PyQt5.QtCore import pyqtProperty, QObject
|
||||||
from typing import Any, Dict, Optional
|
from typing import Any, Dict, Optional
|
||||||
|
|
||||||
from UM.i18n import i18nCatalog # To translate placeholder names if data is not present.
|
from UM.Util import parseBool
|
||||||
|
|
||||||
|
from UM.i18n import i18nCatalog # To translate placeholder names if data is not present.
|
||||||
catalog = i18nCatalog("cura")
|
catalog = i18nCatalog("cura")
|
||||||
|
|
||||||
|
|
||||||
class PackageModel(QObject):
|
class PackageModel(QObject):
|
||||||
"""
|
"""
|
||||||
Represents a package, containing all the relevant information to be displayed about a package.
|
Represents a package, containing all the relevant information to be displayed about a package.
|
||||||
@ -25,17 +27,65 @@ class PackageModel(QObject):
|
|||||||
"""
|
"""
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self._package_id = package_data.get("package_id", "UnknownPackageId")
|
self._package_id = package_data.get("package_id", "UnknownPackageId")
|
||||||
|
|
||||||
|
self._icon_url = package_data.get("icon_url", "")
|
||||||
self._display_name = package_data.get("display_name", catalog.i18nc("@label:property", "Unknown Package"))
|
self._display_name = package_data.get("display_name", catalog.i18nc("@label:property", "Unknown Package"))
|
||||||
|
self._is_verified = "verified" in package_data.get("tags", [])
|
||||||
|
self._package_version = package_data.get("package_version", "") # Display purpose, no need for 'UM.Version'.
|
||||||
|
self._package_info_url = package_data.get("website", "") # Not to be confused with 'download_url'.
|
||||||
|
self._download_count = package_data.get("download_count", 0)
|
||||||
|
self._description = package_data.get("description", "")
|
||||||
|
|
||||||
|
self._download_url = package_data.get("download_url", "") # Not used yet, will be.
|
||||||
|
self._release_notes = package_data.get("release_notes", "") # Not used yet, propose to add to description?
|
||||||
|
|
||||||
|
author_data = package_data.get("author", {})
|
||||||
|
self._author_name = author_data.get("display_name", catalog.i18nc("@label:property", "Unknown Author"))
|
||||||
|
self._author_info_url = author_data.get("website", "")
|
||||||
|
|
||||||
self._section_title = section_title
|
self._section_title = section_title
|
||||||
|
# Note that there's a lot more info in the package_data than just these specified here.
|
||||||
|
|
||||||
@pyqtProperty(str, constant = True)
|
@pyqtProperty(str, constant = True)
|
||||||
def packageId(self) -> str:
|
def packageId(self) -> str:
|
||||||
return self._package_id
|
return self._package_id
|
||||||
|
|
||||||
|
@pyqtProperty(str, constant=True)
|
||||||
|
def iconUrl(self):
|
||||||
|
return self._icon_url
|
||||||
|
|
||||||
@pyqtProperty(str, constant = True)
|
@pyqtProperty(str, constant = True)
|
||||||
def displayName(self) -> str:
|
def displayName(self) -> str:
|
||||||
return self._display_name
|
return self._display_name
|
||||||
|
|
||||||
|
@pyqtProperty(bool, constant=True)
|
||||||
|
def isVerified(self):
|
||||||
|
return self._is_verified
|
||||||
|
|
||||||
|
@pyqtProperty(str, constant=True)
|
||||||
|
def packageVersion(self):
|
||||||
|
return self._package_version
|
||||||
|
|
||||||
|
@pyqtProperty(str, constant=True)
|
||||||
|
def packageInfoUrl(self):
|
||||||
|
return self._package_info_url
|
||||||
|
|
||||||
|
@pyqtProperty(int, constant=True)
|
||||||
|
def downloadCount(self):
|
||||||
|
return self._download_count
|
||||||
|
|
||||||
|
@pyqtProperty(str, constant=True)
|
||||||
|
def description(self):
|
||||||
|
return self._description
|
||||||
|
|
||||||
|
@pyqtProperty(str, constant=True)
|
||||||
|
def authorName(self):
|
||||||
|
return self._author_name
|
||||||
|
|
||||||
|
@pyqtProperty(str, constant=True)
|
||||||
|
def authorInfoUrl(self):
|
||||||
|
return self._author_info_url
|
||||||
|
|
||||||
@pyqtProperty(str, constant = True)
|
@pyqtProperty(str, constant = True)
|
||||||
def sectionTitle(self) -> Optional[str]:
|
def sectionTitle(self) -> Optional[str]:
|
||||||
return self._section_title
|
return self._section_title
|
||||||
|
3
plugins/Marketplace/resources/images/placeholder.svg
Normal file
3
plugins/Marketplace/resources/images/placeholder.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48">
|
||||||
|
<path d="M24,44,7,33.4V14.6L24,4,41,14.6V33.4ZM9,32.3l15,9.3,15-9.3V15.7L24,6.4,9,15.7Z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 184 B |
351
plugins/Marketplace/resources/qml/PackageCard.qml
Normal file
351
plugins/Marketplace/resources/qml/PackageCard.qml
Normal file
@ -0,0 +1,351 @@
|
|||||||
|
// Copyright (c) 2021 Ultimaker B.V.
|
||||||
|
// Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Controls 2.15
|
||||||
|
import QtQuick.Layouts 1.1
|
||||||
|
|
||||||
|
import UM 1.6 as UM
|
||||||
|
import Cura 1.6 as Cura
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
property var packageData
|
||||||
|
|
||||||
|
width: parent ? parent.width - UM.Theme.getSize("default_margin").width : 0
|
||||||
|
height: childrenRect.height
|
||||||
|
|
||||||
|
color: UM.Theme.getColor("main_background")
|
||||||
|
radius: UM.Theme.getSize("default_radius").width
|
||||||
|
|
||||||
|
states:
|
||||||
|
[
|
||||||
|
State
|
||||||
|
{
|
||||||
|
name: "Folded"
|
||||||
|
when: true // TODO
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: downloadCountRow
|
||||||
|
visible: false
|
||||||
|
}
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: descriptionArea
|
||||||
|
visible: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State
|
||||||
|
{
|
||||||
|
name: "Header"
|
||||||
|
when: false // TODO
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: downloadCountRow
|
||||||
|
visible: true
|
||||||
|
}
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
target: descriptionArea
|
||||||
|
visible: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
RowLayout
|
||||||
|
{
|
||||||
|
width: parent.width - UM.Theme.getSize("thin_margin").width * 2
|
||||||
|
height: childrenRect.height + UM.Theme.getSize("thin_margin").height * 2
|
||||||
|
x: UM.Theme.getSize("thin_margin").width
|
||||||
|
y: UM.Theme.getSize("thin_margin").height
|
||||||
|
|
||||||
|
spacing: UM.Theme.getSize("default_margin").width
|
||||||
|
|
||||||
|
Image //Separate column for icon on the left.
|
||||||
|
{
|
||||||
|
Layout.preferredWidth: UM.Theme.getSize("card_icon").width
|
||||||
|
Layout.preferredHeight: UM.Theme.getSize("card_icon").height
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
|
||||||
|
source: packageData.iconUrl != "" ? packageData.iconUrl : "../images/placeholder.svg"
|
||||||
|
}
|
||||||
|
|
||||||
|
Column
|
||||||
|
{
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
|
||||||
|
RowLayout //Title row.
|
||||||
|
{
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
width: parent.width
|
||||||
|
|
||||||
|
Label
|
||||||
|
{
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
|
||||||
|
text: packageData.displayName
|
||||||
|
font: UM.Theme.getFont("medium_bold")
|
||||||
|
color: UM.Theme.getColor("text")
|
||||||
|
}
|
||||||
|
|
||||||
|
Row //Row inside row, but the non-layout version skips invisible elements.
|
||||||
|
{
|
||||||
|
spacing: parent.spacing
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
|
||||||
|
Control
|
||||||
|
{
|
||||||
|
width: UM.Theme.getSize("card_tiny_icon").width
|
||||||
|
height: UM.Theme.getSize("card_tiny_icon").height
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
|
||||||
|
enabled: packageData.isVerified
|
||||||
|
visible: packageData.isVerified
|
||||||
|
|
||||||
|
Cura.ToolTip
|
||||||
|
{
|
||||||
|
tooltipText: catalog.i18nc("@info", "Verified")
|
||||||
|
visible: parent.hovered
|
||||||
|
}
|
||||||
|
|
||||||
|
UM.RecolorImage
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
color: UM.Theme.getColor("primary")
|
||||||
|
source: UM.Theme.getIcon("CheckCircle")
|
||||||
|
}
|
||||||
|
|
||||||
|
//NOTE: Can we link to something here? (Probably a static link explaining what verified is):
|
||||||
|
// onClicked: Qt.openUrlExternally( XXXXXX )
|
||||||
|
}
|
||||||
|
|
||||||
|
Control
|
||||||
|
{
|
||||||
|
width: UM.Theme.getSize("card_tiny_icon").width
|
||||||
|
height: UM.Theme.getSize("card_tiny_icon").height
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
|
||||||
|
enabled: false // remove!
|
||||||
|
visible: false // replace packageInfo.XXXXXX
|
||||||
|
// TODO: waiting for materials card implementation
|
||||||
|
|
||||||
|
Cura.ToolTip
|
||||||
|
{
|
||||||
|
tooltipText: "" // TODO
|
||||||
|
visible: parent.hovered
|
||||||
|
}
|
||||||
|
|
||||||
|
UM.RecolorImage
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
color: UM.Theme.getColor("primary")
|
||||||
|
source: UM.Theme.getIcon("CheckCircle") // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
// onClicked: Qt.openUrlExternally( XXXXXX ) // TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Label
|
||||||
|
{
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
|
||||||
|
text: packageData.packageVersion
|
||||||
|
font: UM.Theme.getFont("default")
|
||||||
|
color: UM.Theme.getColor("text")
|
||||||
|
}
|
||||||
|
|
||||||
|
Button
|
||||||
|
{
|
||||||
|
id: externalLinkButton
|
||||||
|
|
||||||
|
Layout.preferredWidth: UM.Theme.getSize("card_tiny_icon").width
|
||||||
|
Layout.preferredHeight: UM.Theme.getSize("card_tiny_icon").height
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
color: externalLinkButton.hovered ? UM.Theme.getColor("action_button_hovered") : UM.Theme.getColor("detail_background")
|
||||||
|
|
||||||
|
UM.RecolorImage
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
color: externalLinkButton.hovered ? UM.Theme.getColor("text_link") : UM.Theme.getColor("text")
|
||||||
|
source: UM.Theme.getIcon("LinkExternal")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onClicked: Qt.openUrlExternally(packageData.packageInfoUrl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout
|
||||||
|
{
|
||||||
|
id: downloadCountRow
|
||||||
|
|
||||||
|
width: childrenRect.width
|
||||||
|
height: childrenRect.height
|
||||||
|
x: UM.Theme.getSize("thin_margin").width
|
||||||
|
y: UM.Theme.getSize("thin_margin").height
|
||||||
|
|
||||||
|
spacing: UM.Theme.getSize("thin_margin").width
|
||||||
|
|
||||||
|
UM.RecolorImage
|
||||||
|
{
|
||||||
|
id: downloadCountIcon
|
||||||
|
width: UM.Theme.getSize("card_tiny_icon").width
|
||||||
|
height: UM.Theme.getSize("card_tiny_icon").height
|
||||||
|
color: UM.Theme.getColor("icon")
|
||||||
|
|
||||||
|
source: UM.Theme.getIcon("Download")
|
||||||
|
}
|
||||||
|
|
||||||
|
Label
|
||||||
|
{
|
||||||
|
id: downloadCountLabel
|
||||||
|
text: packageData.downloadCount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item
|
||||||
|
{
|
||||||
|
id: descriptionArea
|
||||||
|
width: parent.width
|
||||||
|
height: descriptionLabel.height
|
||||||
|
|
||||||
|
Label
|
||||||
|
{
|
||||||
|
id: descriptionLabel
|
||||||
|
width: parent.width
|
||||||
|
property real lastLineWidth: 0; //Store the width of the last line, to properly position the elision.
|
||||||
|
|
||||||
|
text: packageData.description
|
||||||
|
font: UM.Theme.getFont("medium")
|
||||||
|
color: UM.Theme.getColor("text")
|
||||||
|
maximumLineCount: 2
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
elide: Text.ElideRight
|
||||||
|
|
||||||
|
onLineLaidOut:
|
||||||
|
{
|
||||||
|
if(truncated && line.isLast)
|
||||||
|
{
|
||||||
|
let max_line_width = parent.width - readMoreButton.width - fontMetrics.advanceWidth("… ") - UM.Theme.getSize("default_margin").width;
|
||||||
|
if(line.implicitWidth > max_line_width)
|
||||||
|
{
|
||||||
|
line.width = max_line_width;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
line.width = line.implicitWidth - fontMetrics.advanceWidth("…"); //Truncate the ellipsis. We're adding this ourselves.
|
||||||
|
}
|
||||||
|
descriptionLabel.lastLineWidth = line.implicitWidth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Cura.TertiaryButton
|
||||||
|
{
|
||||||
|
id: readMoreButton
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
height: fontMetrics.height //Height of a single line.
|
||||||
|
|
||||||
|
text: catalog.i18nc("@info", "Read more")
|
||||||
|
iconSource: UM.Theme.getIcon("LinkExternal")
|
||||||
|
|
||||||
|
visible: descriptionLabel.truncated
|
||||||
|
enabled: visible
|
||||||
|
leftPadding: UM.Theme.getSize("default_margin").width
|
||||||
|
rightPadding: UM.Theme.getSize("wide_margin").width
|
||||||
|
textFont: descriptionLabel.font
|
||||||
|
isIconOnRightSide: true
|
||||||
|
|
||||||
|
// NOTE: Is this the right URL for this action?
|
||||||
|
onClicked: Qt.openUrlExternally(packageData.packageInfoUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
Label
|
||||||
|
{
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: descriptionLabel.lastLineWidth
|
||||||
|
anchors.bottom: readMoreButton.bottom
|
||||||
|
|
||||||
|
text: "… "
|
||||||
|
font: descriptionLabel.font
|
||||||
|
color: descriptionLabel.color
|
||||||
|
visible: descriptionLabel.truncated
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout //Author and action buttons.
|
||||||
|
{
|
||||||
|
width: parent.width
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
spacing: UM.Theme.getSize("thin_margin").width
|
||||||
|
|
||||||
|
Label
|
||||||
|
{
|
||||||
|
id: authorBy
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
|
||||||
|
text: catalog.i18nc("@label", "By")
|
||||||
|
font: UM.Theme.getFont("default")
|
||||||
|
color: UM.Theme.getColor("text")
|
||||||
|
}
|
||||||
|
|
||||||
|
Cura.TertiaryButton
|
||||||
|
{
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: authorBy.height
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
|
||||||
|
text: packageData.authorName
|
||||||
|
textFont: UM.Theme.getFont("default_bold")
|
||||||
|
textColor: UM.Theme.getColor("text") // override normal link color
|
||||||
|
leftPadding: 0
|
||||||
|
rightPadding: 0
|
||||||
|
iconSource: UM.Theme.getIcon("LinkExternal")
|
||||||
|
isIconOnRightSide: true
|
||||||
|
|
||||||
|
onClicked: Qt.openUrlExternally(packageData.authorInfoUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
Cura.SecondaryButton
|
||||||
|
{
|
||||||
|
id: disableButton
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
text: catalog.i18nc("@button", "Disable")
|
||||||
|
visible: false // not functional right now, also only when unfolding and required
|
||||||
|
}
|
||||||
|
|
||||||
|
Cura.SecondaryButton
|
||||||
|
{
|
||||||
|
id: uninstallButton
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
text: catalog.i18nc("@button", "Uninstall")
|
||||||
|
visible: false // not functional right now, also only when unfolding and required
|
||||||
|
}
|
||||||
|
|
||||||
|
Cura.PrimaryButton
|
||||||
|
{
|
||||||
|
id: installButton
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
text: catalog.i18nc("@button", "Update") // OR Download, if new!
|
||||||
|
visible: false // not functional right now, also only when unfolding and required
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FontMetrics
|
||||||
|
{
|
||||||
|
id: fontMetrics
|
||||||
|
font: UM.Theme.getFont("medium")
|
||||||
|
}
|
||||||
|
}
|
@ -46,24 +46,9 @@ ScrollView
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate: Rectangle
|
delegate: PackageCard
|
||||||
{
|
{
|
||||||
width: packagesListview.width
|
packageData: model.package
|
||||||
height: UM.Theme.getSize("card").height
|
|
||||||
|
|
||||||
color: UM.Theme.getColor("main_background")
|
|
||||||
radius: UM.Theme.getSize("default_radius").width
|
|
||||||
|
|
||||||
Label
|
|
||||||
{
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.leftMargin: Math.round((parent.height - height) / 2)
|
|
||||||
|
|
||||||
text: model.package.displayName
|
|
||||||
font: UM.Theme.getFont("medium_bold")
|
|
||||||
color: UM.Theme.getColor("text")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Wrapper item to add spacing between content and footer.
|
//Wrapper item to add spacing between content and footer.
|
||||||
|
@ -38,7 +38,7 @@ ToolTip
|
|||||||
onAboutToHide: hide()
|
onAboutToHide: hide()
|
||||||
|
|
||||||
// If the text is not set, just set the height to 0 to prevent it from showing
|
// If the text is not set, just set the height to 0 to prevent it from showing
|
||||||
height: text != "" ? label.contentHeight + 2 * UM.Theme.getSize("thin_margin").width: 0
|
height: label.contentHeight + 2 * UM.Theme.getSize("thin_margin").width
|
||||||
|
|
||||||
x:
|
x:
|
||||||
{
|
{
|
||||||
@ -74,7 +74,7 @@ ToolTip
|
|||||||
}
|
}
|
||||||
|
|
||||||
function show() {
|
function show() {
|
||||||
opacity = 1
|
opacity = text != "" ? 1 : 0
|
||||||
}
|
}
|
||||||
|
|
||||||
function hide() {
|
function hide() {
|
||||||
|
3
resources/themes/cura-light/icons/default/Download.svg
Normal file
3
resources/themes/cura-light/icons/default/Download.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M18.707 10.293L12 17L5.293 10.293L6.707 8.8789L11 13.1719V3H13V13.1719L17.293 8.8789L18.707 10.293ZM21 19H3V21H21V19Z" fill="#000E1A"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 248 B |
@ -553,7 +553,10 @@
|
|||||||
|
|
||||||
"standard_list_lineheight": [1.5, 1.5],
|
"standard_list_lineheight": [1.5, 1.5],
|
||||||
"standard_arrow": [1.0, 1.0],
|
"standard_arrow": [1.0, 1.0],
|
||||||
|
|
||||||
"card": [25.0, 8.75],
|
"card": [25.0, 8.75],
|
||||||
|
"card_icon": [6.0, 6.0],
|
||||||
|
"card_tiny_icon": [1.2, 1.2],
|
||||||
|
|
||||||
"button": [4, 4],
|
"button": [4, 4],
|
||||||
"button_icon": [2.5, 2.5],
|
"button_icon": [2.5, 2.5],
|
||||||
|
Loading…
x
Reference in New Issue
Block a user