diff --git a/plugins/Marketplace/PackageModel.py b/plugins/Marketplace/PackageModel.py
index 62558a51b8..d123550c28 100644
--- a/plugins/Marketplace/PackageModel.py
+++ b/plugins/Marketplace/PackageModel.py
@@ -1,11 +1,14 @@
# Copyright (c) 2021 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
-from PyQt5.QtCore import pyqtProperty, pyqtSignal, QObject
-from typing import Any, Dict, Optional
+from PyQt5.QtCore import pyqtProperty, QObject, pyqtSignal
+import re
+from typing import Any, Dict, List, Optional
+from cura.Settings.CuraContainerRegistry import CuraContainerRegistry # To get names of materials we're compatible with.
from UM.Logger import Logger
from UM.i18n import i18nCatalog # To translate placeholder names if data is not present.
+
catalog = i18nCatalog("cura")
@@ -39,10 +42,20 @@ class PackageModel(QObject):
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._formatted_description = self._format(self._description)
- self._download_url = package_data.get("download_url", "") # Not used yet, will be.
+ self._download_url = package_data.get("download_url", "")
self._release_notes = package_data.get("release_notes", "") # Not used yet, propose to add to description?
+ subdata = package_data.get("data", {})
+ self._technical_data_sheet = self._findLink(subdata, "technical_data_sheet")
+ self._safety_data_sheet = self._findLink(subdata, "safety_data_sheet")
+ self._where_to_buy = self._findLink(subdata, "where_to_buy")
+ self._compatible_printers = self._getCompatiblePrinters(subdata)
+ self._compatible_support_materials = self._getCompatibleSupportMaterials(subdata)
+ self._is_compatible_material_station = self._isCompatibleMaterialStation(subdata)
+ self._is_compatible_air_manager = self._isCompatibleAirManager(subdata)
+
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", "")
@@ -53,6 +66,111 @@ class PackageModel(QObject):
self._section_title = section_title
# Note that there's a lot more info in the package_data than just these specified here.
+ def _findLink(self, subdata: Dict[str, Any], link_type: str) -> str:
+ """
+ Searches the package data for a link of a certain type.
+
+ The links are not in a fixed path in the package data. We need to iterate over the available links to find them.
+ :param subdata: The "data" element in the package data, which should contain links.
+ :param link_type: The type of link to find.
+ :return: A URL of where the link leads, or an empty string if there is no link of that type in the package data.
+ """
+ links = subdata.get("links", [])
+ for link in links:
+ if link.get("type", "") == link_type:
+ return link.get("url", "")
+ else:
+ return "" # No link with the correct type was found.
+
+ def _format(self, text: str) -> str:
+ """
+ Formats a user-readable block of text for display.
+ :return: A block of rich text with formatting embedded.
+ """
+ # Turn all in-line hyperlinks into actual links.
+ url_regex = re.compile(r"(((http|https)://)[a-zA-Z0-9@:%.\-_+~#?&/=]{2,256}\.[a-z]{2,12}(/[a-zA-Z0-9@:%.\-_+~#?&/=]*)?)")
+ text = re.sub(url_regex, r'\1', text)
+
+ # Turn newlines into
so that they get displayed as newlines when rendering as rich text.
+ text = text.replace("\n", "
")
+
+ return text
+
+ def _getCompatiblePrinters(self, subdata: Dict[str, Any]) -> List[str]:
+ """
+ Gets the list of printers that this package provides material compatibility with.
+
+ Any printer is listed, even if it's only for a single nozzle on a single material in the package.
+ :param subdata: The "data" element in the package data, which should contain this compatibility information.
+ :return: A list of printer names that this package provides material compatibility with.
+ """
+ result = set()
+
+ for material in subdata.get("materials", []):
+ for compatibility in material.get("compatibility", []):
+ printer_name = compatibility.get("machine_name")
+ if printer_name is None:
+ continue # Missing printer name information. Skip this one.
+ for subcompatibility in compatibility.get("compatibilities", []):
+ if subcompatibility.get("hardware_compatible", False):
+ result.add(printer_name)
+ break
+
+ return list(sorted(result))
+
+ def _getCompatibleSupportMaterials(self, subdata: Dict[str, Any]) -> List[str]:
+ """
+ Gets the list of support materials that the materials in this package are compatible with.
+
+ Since the materials are individually encoded as keys in the API response, only PVA and Breakaway are currently
+ supported.
+ :param subdata: The "data" element in the package data, which should contain this compatibility information.
+ :return: A list of support materials that the materials in this package are compatible with.
+ """
+ result = set()
+
+ container_registry = CuraContainerRegistry.getInstance()
+ try:
+ pva_name = container_registry.findContainersMetadata(id = "ultimaker_pva")[0].get("name", "Ultimaker PVA")
+ except IndexError:
+ pva_name = "Ultimaker PVA"
+ try:
+ breakaway_name = container_registry.findContainersMetadata(id = "ultimaker_bam")[0].get("name", "Ultimaker Breakaway")
+ except IndexError:
+ breakaway_name = "Ultimaker Breakaway"
+
+ for material in subdata.get("materials", []):
+ if material.get("pva_compatible", False):
+ result.add(pva_name)
+ if material.get("breakaway_compatible", False):
+ result.add(breakaway_name)
+
+ return list(sorted(result))
+
+ def _isCompatibleMaterialStation(self, subdata: Dict[str, Any]) -> bool:
+ """
+ Finds out if this package provides any material that is compatible with the material station.
+ :param subdata: The "data" element in the package data, which should contain this compatibility information.
+ :return: Whether this package provides any material that is compatible with the material station.
+ """
+ for material in subdata.get("materials", []):
+ for compatibility in material.get("compatibility", []):
+ if compatibility.get("material_station_optimized", False):
+ return True
+ return False
+
+ def _isCompatibleAirManager(self, subdata: Dict[str, Any]) -> bool:
+ """
+ Finds out if this package provides any material that is compatible with the air manager.
+ :param subdata: The "data" element in the package data, which should contain this compatibility information.
+ :return: Whether this package provides any material that is compatible with the air manager.
+ """
+ for material in subdata.get("materials", []):
+ for compatibility in material.get("compatibility", []):
+ if compatibility.get("air_manager_optimized", False):
+ return True
+ return False
+
@pyqtProperty(str, constant = True)
def packageId(self) -> str:
return self._package_id
@@ -89,6 +207,10 @@ class PackageModel(QObject):
def description(self):
return self._description
+ @pyqtProperty(str, constant = True)
+ def formattedDescription(self) -> str:
+ return self._formatted_description
+
@pyqtProperty(str, constant=True)
def authorName(self):
return self._author_name
@@ -105,6 +227,34 @@ class PackageModel(QObject):
def sectionTitle(self) -> Optional[str]:
return self._section_title
+ @pyqtProperty(str, constant = True)
+ def technicalDataSheet(self) -> str:
+ return self._technical_data_sheet
+
+ @pyqtProperty(str, constant = True)
+ def safetyDataSheet(self) -> str:
+ return self._safety_data_sheet
+
+ @pyqtProperty(str, constant = True)
+ def whereToBuy(self) -> str:
+ return self._where_to_buy
+
+ @pyqtProperty("QStringList", constant = True)
+ def compatiblePrinters(self) -> List[str]:
+ return self._compatible_printers
+
+ @pyqtProperty("QStringList", constant = True)
+ def compatibleSupportMaterials(self) -> List[str]:
+ return self._compatible_support_materials
+
+ @pyqtProperty(bool, constant = True)
+ def isCompatibleMaterialStation(self) -> bool:
+ return self._is_compatible_material_station
+
+ @pyqtProperty(bool, constant = True)
+ def isCompatibleAirManager(self) -> bool:
+ return self._is_compatible_air_manager
+
isInstalledChanged = pyqtSignal()
@pyqtProperty(bool, notify = isInstalledChanged)
diff --git a/plugins/Marketplace/resources/qml/Marketplace.qml b/plugins/Marketplace/resources/qml/Marketplace.qml
index bee825d955..44f7777b35 100644
--- a/plugins/Marketplace/resources/qml/Marketplace.qml
+++ b/plugins/Marketplace/resources/qml/Marketplace.qml
@@ -86,6 +86,15 @@ Window
}
}
+ OnboardBanner
+ {
+ visible: content.item && content.item.bannerVisible
+ text: content.item && content.item.bannerText
+ icon: content.item && content.item.bannerIcon
+ onRemove: content.item && content.item.onRemoveBanner
+ readMoreUrl: content.item && content.item.bannerReadMoreUrl
+ }
+
// Search & Top-Level Tabs
Item
{
@@ -167,6 +176,25 @@ Window
}
}
+ FontMetrics
+ {
+ id: fontMetrics
+ font: UM.Theme.getFont("default")
+ }
+
+ Cura.TertiaryButton
+ {
+ text: catalog.i18nc("@info", "Search in the browser")
+ iconSource: UM.Theme.getIcon("LinkExternal")
+ visible: pageSelectionTabBar.currentItem.hasSearch
+ isIconOnRightSide: true
+ height: fontMetrics.height
+ textFont: fontMetrics.font
+ textColor: UM.Theme.getColor("text")
+
+ onClicked: content.item && Qt.openUrlExternally(content.item.searchInBrowserUrl)
+ }
+
// Page contents.
Rectangle
{
diff --git a/plugins/Marketplace/resources/qml/PackageCard.qml b/plugins/Marketplace/resources/qml/PackageCard.qml
index b8c053b5bb..b8f815bedf 100644
--- a/plugins/Marketplace/resources/qml/PackageCard.qml
+++ b/plugins/Marketplace/resources/qml/PackageCard.qml
@@ -13,7 +13,7 @@ Rectangle
property var packageData
property bool expanded: false
- height: UM.Theme.getSize("card").height
+ height: childrenRect.height
color: UM.Theme.getColor("main_background")
radius: UM.Theme.getSize("default_radius").width
@@ -25,9 +25,19 @@ Rectangle
when: !expanded
PropertyChanges
{
- target: descriptionArea
+ target: shortDescription
visible: true
}
+ PropertyChanges
+ {
+ target: downloadCount
+ visible: false
+ }
+ PropertyChanges
+ {
+ target: extendedDescription
+ visible: false
+ }
},
State
{
@@ -35,295 +45,563 @@ Rectangle
when: expanded
PropertyChanges
{
- target: descriptionArea
+ target: shortDescription
visible: false
}
+ PropertyChanges
+ {
+ target: downloadCount
+ visible: true
+ }
+ PropertyChanges
+ {
+ target: extendedDescription
+ visible: true
+ }
}
]
- // Separate column for icon on the left.
- Image
+ Column
{
- id: packageItem
- anchors
- {
- top: parent.top
- left: parent.left
- margins: UM.Theme.getSize("default_margin").width
- }
- width: UM.Theme.getSize("card_icon").width
- height: width
-
- source: packageData.iconUrl != "" ? packageData.iconUrl : "../images/placeholder.svg"
- }
-
- // Title row.
- RowLayout
- {
- id: titleBar
- anchors
- {
- left: packageItem.right
- right: parent.right
- top: parent.top
- topMargin: UM.Theme.getSize("narrow_margin").height
- leftMargin: UM.Theme.getSize("default_margin").width
- rightMargin:UM.Theme.getSize("thick_margin").width
- }
-
- Label
- {
- text: packageData.displayName
- font: UM.Theme.getFont("medium_bold")
- color: UM.Theme.getColor("text")
- verticalAlignment: Text.AlignTop
- }
-
- Control
- {
- Layout.preferredWidth: UM.Theme.getSize("card_tiny_icon").width
- Layout.preferredHeight: UM.Theme.getSize("card_tiny_icon").height
-
-
- enabled: packageData.isCheckedByUltimaker
- visible: packageData.isCheckedByUltimaker
-
- Cura.ToolTip
- {
- tooltipText:
- {
- switch(packageData.packageType)
- {
- case "plugin": return catalog.i18nc("@info", "Ultimaker Verified Plug-in");
- case "material": return catalog.i18nc("@info", "Ultimaker Certified Material");
- default: return catalog.i18nc("@info", "Ultimaker Verified Package");
- }
- }
- visible: parent.hovered
- targetPoint: Qt.point(0, Math.round(parent.y + parent.height / 2))
- }
-
- Rectangle
- {
- anchors.fill: parent
- color: UM.Theme.getColor("action_button_hovered")
- radius: width
- UM.RecolorImage
- {
- anchors.fill: parent
- color: UM.Theme.getColor("primary")
- source: packageData.packageType == "plugin" ? UM.Theme.getIcon("CheckCircle") : UM.Theme.getIcon("Certified")
- }
- }
-
- //NOTE: Can we link to something here? (Probably a static link explaining what verified is):
- // onClicked: Qt.openUrlExternally( XXXXXX )
- }
-
- Control
- {
- Layout.preferredWidth: UM.Theme.getSize("card_tiny_icon").width
- Layout.preferredHeight: UM.Theme.getSize("card_tiny_icon").height
- Layout.alignment: Qt.AlignCenter
- 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
- {
- id: packageVersionLabel
- text: packageData.packageVersion
- font: UM.Theme.getFont("default")
- color: UM.Theme.getColor("text")
- Layout.fillWidth: true
- }
-
- Button
- {
- id: externalLinkButton
-
- // For some reason if i set padding, they don't match up. If i set all of them explicitly, it does work?
- leftPadding: UM.Theme.getSize("narrow_margin").width
- rightPadding: UM.Theme.getSize("narrow_margin").width
- topPadding: UM.Theme.getSize("narrow_margin").width
- bottomPadding: UM.Theme.getSize("narrow_margin").width
-
- Layout.preferredWidth: UM.Theme.getSize("card_tiny_icon").width + 2 * padding
- Layout.preferredHeight: UM.Theme.getSize("card_tiny_icon").width + 2 * padding
- contentItem: UM.RecolorImage
- {
- source: UM.Theme.getIcon("LinkExternal")
- color: UM.Theme.getColor("icon")
- implicitWidth: UM.Theme.getSize("card_tiny_icon").width
- implicitHeight: UM.Theme.getSize("card_tiny_icon").height
- }
-
- background: Rectangle
- {
- color: externalLinkButton.hovered ? UM.Theme.getColor("action_button_hovered"): "transparent"
- radius: externalLinkButton.width / 2
- }
- onClicked: Qt.openUrlExternally(packageData.authorInfoUrl)
- }
-
- }
-
- // Description area
- Item
- {
- id: descriptionArea
- height: childrenRect.height > descriptionLabel.height ? childrenRect.height : descriptionLabel.height
- anchors
- {
- top: titleBar.bottom
- left: packageItem.right
- right: parent.right
- rightMargin: UM.Theme.getSize("default_margin").width
- leftMargin: UM.Theme.getSize("default_margin").width
- }
- 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("default")
- 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("… ") - 2 * 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;
- }
- }
- }
- Label
- {
- id: tripleDotLabel
- anchors.left: parent.left
- anchors.leftMargin: descriptionLabel.lastLineWidth
- anchors.bottom: readMoreButton.bottom
-
- text: "… "
- font: descriptionLabel.font
- color: descriptionLabel.color
- visible: descriptionLabel.truncated
- }
- Cura.TertiaryButton
- {
- id: readMoreButton
- anchors.left: tripleDotLabel.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
-
- onClicked: Qt.openUrlExternally(packageData.packageInfoUrl)
- }
- }
-
- // Author and action buttons.
- RowLayout
- {
- id: authorAndActionButton
width: parent.width
- anchors
- {
- bottom: parent.bottom
- left: packageItem.right
- right: parent.right
- margins: UM.Theme.getSize("default_margin").height
- }
- spacing: UM.Theme.getSize("narrow_margin").width
- Label
- {
- id: authorBy
- Layout.alignment: Qt.AlignVCenter
+ spacing: 0
- text: catalog.i18nc("@label", "By")
- font: UM.Theme.getFont("default")
- color: UM.Theme.getColor("text")
+ Item
+ {
+ width: parent.width
+ height: UM.Theme.getSize("card").height
+
+ Image
+ {
+ id: packageItem
+ anchors
+ {
+ top: parent.top
+ left: parent.left
+ margins: UM.Theme.getSize("default_margin").width
+ }
+ width: UM.Theme.getSize("card_icon").width
+ height: width
+
+ source: packageData.iconUrl != "" ? packageData.iconUrl : "../images/placeholder.svg"
+ }
+
+ ColumnLayout
+ {
+ anchors
+ {
+ left: packageItem.right
+ leftMargin: UM.Theme.getSize("default_margin").width
+ right: parent.right
+ rightMargin: UM.Theme.getSize("thick_margin").width
+ top: parent.top
+ topMargin: UM.Theme.getSize("narrow_margin").height
+ }
+ height: packageItem.height + packageItem.anchors.margins * 2
+
+ // Title row.
+ RowLayout
+ {
+ id: titleBar
+ Layout.preferredWidth: parent.width
+ Layout.preferredHeight: childrenRect.height
+
+ Label
+ {
+ text: packageData.displayName
+ font: UM.Theme.getFont("medium_bold")
+ color: UM.Theme.getColor("text")
+ verticalAlignment: Text.AlignTop
+ }
+
+ Control
+ {
+ Layout.preferredWidth: UM.Theme.getSize("card_tiny_icon").width
+ Layout.preferredHeight: UM.Theme.getSize("card_tiny_icon").height
+
+ enabled: packageData.isCheckedByUltimaker
+ visible: packageData.isCheckedByUltimaker
+
+ Cura.ToolTip
+ {
+ tooltipText:
+ {
+ switch(packageData.packageType)
+ {
+ case "plugin": return catalog.i18nc("@info", "Ultimaker Verified Plug-in");
+ case "material": return catalog.i18nc("@info", "Ultimaker Certified Material");
+ default: return catalog.i18nc("@info", "Ultimaker Verified Package");
+ }
+ }
+ visible: parent.hovered
+ targetPoint: Qt.point(0, Math.round(parent.y + parent.height / 4))
+ }
+
+ Rectangle
+ {
+ anchors.fill: parent
+ color: UM.Theme.getColor("action_button_hovered")
+ radius: width
+ UM.RecolorImage
+ {
+ anchors.fill: parent
+ color: UM.Theme.getColor("primary")
+ source: packageData.packageType == "plugin" ? UM.Theme.getIcon("CheckCircle") : UM.Theme.getIcon("Certified")
+ }
+ }
+
+ //NOTE: Can we link to something here? (Probably a static link explaining what verified is):
+ // onClicked: Qt.openUrlExternally( XXXXXX )
+ }
+
+ Control
+ {
+ Layout.preferredWidth: UM.Theme.getSize("card_tiny_icon").width
+ Layout.preferredHeight: UM.Theme.getSize("card_tiny_icon").height
+ Layout.alignment: Qt.AlignCenter
+ 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
+ {
+ id: packageVersionLabel
+ text: packageData.packageVersion
+ font: UM.Theme.getFont("default")
+ color: UM.Theme.getColor("text")
+ Layout.fillWidth: true
+ }
+
+ Button
+ {
+ id: externalLinkButton
+
+ // For some reason if i set padding, they don't match up. If i set all of them explicitly, it does work?
+ leftPadding: UM.Theme.getSize("narrow_margin").width
+ rightPadding: UM.Theme.getSize("narrow_margin").width
+ topPadding: UM.Theme.getSize("narrow_margin").width
+ bottomPadding: UM.Theme.getSize("narrow_margin").width
+
+ Layout.preferredWidth: UM.Theme.getSize("card_tiny_icon").width + 2 * padding
+ Layout.preferredHeight: UM.Theme.getSize("card_tiny_icon").width + 2 * padding
+ contentItem: UM.RecolorImage
+ {
+ source: UM.Theme.getIcon("LinkExternal")
+ color: UM.Theme.getColor("icon")
+ implicitWidth: UM.Theme.getSize("card_tiny_icon").width
+ implicitHeight: UM.Theme.getSize("card_tiny_icon").height
+ }
+
+ background: Rectangle
+ {
+ color: externalLinkButton.hovered ? UM.Theme.getColor("action_button_hovered"): "transparent"
+ radius: externalLinkButton.width / 2
+ }
+ onClicked: Qt.openUrlExternally(packageData.authorInfoUrl)
+ }
+ }
+
+ Item
+ {
+ id: shortDescription
+ Layout.preferredWidth: parent.width
+ Layout.fillHeight: true
+
+ 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
+ textFormat: Text.PlainText //Must be plain text, or we won't get onLineLaidOut signals. Don't auto-detect!
+ font: UM.Theme.getFont("default")
+ color: UM.Theme.getColor("text")
+ maximumLineCount: 2
+ wrapMode: Text.Wrap
+ elide: Text.ElideRight
+ visible: text !== ""
+
+ onLineLaidOut:
+ {
+ if(truncated && line.isLast)
+ {
+ let max_line_width = parent.width - readMoreButton.width - fontMetrics.advanceWidth("… ") - 2 * 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;
+ }
+ }
+ }
+ Label
+ {
+ id: tripleDotLabel
+ anchors.left: parent.left
+ anchors.leftMargin: descriptionLabel.lastLineWidth
+ anchors.bottom: descriptionLabel.bottom
+
+ text: "… "
+ font: descriptionLabel.font
+ color: descriptionLabel.color
+ visible: descriptionLabel.truncated && descriptionLabel.text !== ""
+ }
+ 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 && descriptionLabel.text !== ""
+ enabled: visible
+ leftPadding: UM.Theme.getSize("default_margin").width
+ rightPadding: UM.Theme.getSize("wide_margin").width
+ textFont: descriptionLabel.font
+ isIconOnRightSide: true
+
+ onClicked: Qt.openUrlExternally(packageData.packageInfoUrl)
+ }
+ }
+
+ Row
+ {
+ id: downloadCount
+ Layout.preferredWidth: parent.width
+ Layout.fillHeight: true
+
+ UM.RecolorImage
+ {
+ id: downloadsIcon
+ width: UM.Theme.getSize("card_tiny_icon").width
+ height: UM.Theme.getSize("card_tiny_icon").height
+
+ visible: packageData.installationStatus !== "bundled" //Don't show download count for packages that are bundled. It'll usually be 0.
+ source: UM.Theme.getIcon("Download")
+ color: UM.Theme.getColor("text")
+ }
+
+ Label
+ {
+ anchors.verticalCenter: downloadsIcon.verticalCenter
+
+ visible: packageData.installationStatus !== "bundled" //Don't show download count for packages that are bundled. It'll usually be 0.
+ color: UM.Theme.getColor("text")
+ font: UM.Theme.getFont("default")
+ text: packageData.downloadCount
+ }
+ }
+
+ // Author and action buttons.
+ RowLayout
+ {
+ id: authorAndActionButton
+ Layout.preferredWidth: parent.width
+ Layout.preferredHeight: childrenRect.height
+
+ spacing: UM.Theme.getSize("narrow_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
+ }
+ }
+ }
}
- Cura.TertiaryButton
+ Column
{
- Layout.fillWidth: true
- Layout.preferredHeight: authorBy.height
- Layout.alignment: Qt.AlignVCenter
+ id: extendedDescription
+ width: parent.width
- 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
+ padding: UM.Theme.getSize("default_margin").width
+ topPadding: 0
+ spacing: UM.Theme.getSize("default_margin").height
- onClicked: Qt.openUrlExternally(packageData.authorInfoUrl)
- }
+ Label
+ {
+ width: parent.width - parent.padding * 2
- Cura.SecondaryButton
- {
- id: enableManageButton
- Layout.alignment: Qt.AlignTop
- text: packageData.enableManageButtonText
- visible: packageData.enableManageButtonVisible
- }
+ text: catalog.i18nc("@header", "Description")
+ font: UM.Theme.getFont("medium_bold")
+ color: UM.Theme.getColor("text")
+ elide: Text.ElideRight
+ }
- Cura.SecondaryButton
- {
- id: installManageButton
- Layout.alignment: Qt.AlignTop
- text: packageData.installManageButtonText
- visible: packageData.installManageButtonVisible
- }
+ Label
+ {
+ width: parent.width - parent.padding * 2
- Cura.PrimaryButton
- {
- id: updateManageButton
- Layout.alignment: Qt.AlignTop
- text: catalog.i18nc("@button", "Update") // OR Download, if new!
- visible: packageData.updateManageButtonVisible
+ text: packageData.formattedDescription
+ font: UM.Theme.getFont("medium")
+ color: UM.Theme.getColor("text")
+ linkColor: UM.Theme.getColor("text_link")
+ wrapMode: Text.Wrap
+ textFormat: Text.RichText
+
+ onLinkActivated: UM.UrlUtil.openUrl(link, ["http", "https"])
+ }
+
+ Column //Separate column to have no spacing between compatible printers.
+ {
+ id: compatiblePrinterColumn
+ width: parent.width - parent.padding * 2
+
+ visible: packageData.packageType === "material"
+ spacing: 0
+
+ Label
+ {
+ width: parent.width
+
+ text: catalog.i18nc("@header", "Compatible printers")
+ font: UM.Theme.getFont("medium_bold")
+ color: UM.Theme.getColor("text")
+ elide: Text.ElideRight
+ }
+
+ Repeater
+ {
+ model: packageData.compatiblePrinters
+
+ Label
+ {
+ width: compatiblePrinterColumn.width
+
+ text: modelData
+ font: UM.Theme.getFont("medium")
+ color: UM.Theme.getColor("text")
+ elide: Text.ElideRight
+ }
+ }
+
+ Label
+ {
+ width: parent.width
+
+ visible: packageData.compatiblePrinters.length == 0
+ text: "(" + catalog.i18nc("@info", "No compatibility information") + ")"
+ font: UM.Theme.getFont("medium")
+ color: UM.Theme.getColor("text")
+ elide: Text.ElideRight
+ }
+ }
+
+ Column
+ {
+ id: compatibleSupportMaterialColumn
+ width: parent.width - parent.padding * 2
+
+ visible: packageData.packageType === "material"
+ spacing: 0
+
+ Label
+ {
+ width: parent.width
+
+ text: catalog.i18nc("@header", "Compatible support materials")
+ font: UM.Theme.getFont("medium_bold")
+ color: UM.Theme.getColor("text")
+ elide: Text.ElideRight
+ }
+
+ Repeater
+ {
+ model: packageData.compatibleSupportMaterials
+
+ Label
+ {
+ width: compatibleSupportMaterialColumn.width
+
+ text: modelData
+ font: UM.Theme.getFont("medium")
+ color: UM.Theme.getColor("text")
+ elide: Text.ElideRight
+ }
+ }
+
+ Label
+ {
+ width: parent.width
+
+ visible: packageData.compatibleSupportMaterials.length == 0
+ text: "(" + catalog.i18nc("@info No materials", "None") + ")"
+ font: UM.Theme.getFont("medium")
+ color: UM.Theme.getColor("text")
+ elide: Text.ElideRight
+ }
+ }
+
+ Column
+ {
+ width: parent.width - parent.padding * 2
+
+ visible: packageData.packageType === "material"
+ spacing: 0
+
+ Label
+ {
+ width: parent.width
+
+ text: catalog.i18nc("@header", "Compatible with Material Station")
+ font: UM.Theme.getFont("medium_bold")
+ color: UM.Theme.getColor("text")
+ elide: Text.ElideRight
+ }
+
+ Label
+ {
+ width: parent.width
+
+ text: packageData.isCompatibleMaterialStation ? catalog.i18nc("@info", "Yes") : catalog.i18nc("@info", "No")
+ font: UM.Theme.getFont("medium")
+ color: UM.Theme.getColor("text")
+ elide: Text.ElideRight
+ }
+ }
+
+ Column
+ {
+ width: parent.width - parent.padding * 2
+
+ visible: packageData.packageType === "material"
+ spacing: 0
+
+ Label
+ {
+ width: parent.width
+
+ text: catalog.i18nc("@header", "Optimized for Air Manager")
+ font: UM.Theme.getFont("medium_bold")
+ color: UM.Theme.getColor("text")
+ elide: Text.ElideRight
+ }
+
+ Label
+ {
+ width: parent.width
+
+ text: packageData.isCompatibleAirManager ? catalog.i18nc("@info", "Yes") : catalog.i18nc("@info", "No")
+ font: UM.Theme.getFont("medium")
+ color: UM.Theme.getColor("text")
+ elide: Text.ElideRight
+ }
+ }
+
+ Row
+ {
+ id: externalButtonRow
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ spacing: UM.Theme.getSize("narrow_margin").width
+
+ Cura.SecondaryButton
+ {
+ text: packageData.packageType === "plugin" ? catalog.i18nc("@button", "Visit plug-in website") : catalog.i18nc("@button", "Website")
+ iconSource: UM.Theme.getIcon("Globe")
+ outlineColor: "transparent"
+ onClicked: Qt.openUrlExternally(packageData.packageInfoUrl)
+ }
+
+ Cura.SecondaryButton
+ {
+ visible: packageData.packageType === "material"
+ text: catalog.i18nc("@button", "Buy spool")
+ iconSource: UM.Theme.getIcon("ShoppingCart")
+ outlineColor: "transparent"
+ onClicked: Qt.openUrlExternally(packageData.whereToBuy)
+ }
+
+ Cura.SecondaryButton
+ {
+ visible: packageData.packageType === "material"
+ text: catalog.i18nc("@button", "Safety datasheet")
+ iconSource: UM.Theme.getIcon("Warning")
+ outlineColor: "transparent"
+ onClicked: Qt.openUrlExternally(packageData.safetyDataSheet)
+ }
+
+ Cura.SecondaryButton
+ {
+ visible: packageData.packageType === "material"
+ text: catalog.i18nc("@button", "Technical datasheet")
+ iconSource: UM.Theme.getIcon("DocumentFilled")
+ outlineColor: "transparent"
+ onClicked: Qt.openUrlExternally(packageData.technicalDataSheet)
+ }
+ }
}
}
diff --git a/plugins/Marketplace/resources/qml/Packages.qml b/plugins/Marketplace/resources/qml/Packages.qml
index 275792ed42..c240141a71 100644
--- a/plugins/Marketplace/resources/qml/Packages.qml
+++ b/plugins/Marketplace/resources/qml/Packages.qml
@@ -13,6 +13,12 @@ ListView
property string pageTitle
property var selectedPackage
+ property string searchInBrowserUrl
+ property bool bannerVisible
+ property var bannerIcon
+ property string bannerText
+ property string bannerReadMoreUrl
+ property var onRemoveBanner
clip: true