mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-14 18:27:51 -06:00
Merge remote-tracking branch 'origin/marketplace_redesign' into CURA-8587_disable_update_install_and_uninstall
# Conflicts: # plugins/Marketplace/LocalPackageList.py # plugins/Marketplace/PackageModel.py # plugins/Marketplace/RemotePackageList.py # plugins/Marketplace/resources/qml/Marketplace.qml # plugins/Marketplace/resources/qml/PackageCard.qml # plugins/Marketplace/resources/qml/Packages.qml
This commit is contained in:
commit
4fef2de71c
4 changed files with 739 additions and 277 deletions
|
@ -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'<a href="\1">\1</a>', text)
|
||||
|
||||
# Turn newlines into <br> so that they get displayed as newlines when rendering as rich text.
|
||||
text = text.replace("\n", "<br>")
|
||||
|
||||
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)
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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,13 +45,33 @@ 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.
|
||||
Column
|
||||
{
|
||||
width: parent.width
|
||||
|
||||
spacing: 0
|
||||
|
||||
Item
|
||||
{
|
||||
width: parent.width
|
||||
height: UM.Theme.getSize("card").height
|
||||
|
||||
Image
|
||||
{
|
||||
id: packageItem
|
||||
|
@ -57,19 +87,25 @@ Rectangle
|
|||
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
|
||||
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
|
||||
}
|
||||
Layout.preferredWidth: parent.width
|
||||
Layout.preferredHeight: childrenRect.height
|
||||
|
||||
Label
|
||||
{
|
||||
|
@ -84,7 +120,6 @@ Rectangle
|
|||
Layout.preferredWidth: UM.Theme.getSize("card_tiny_icon").width
|
||||
Layout.preferredHeight: UM.Theme.getSize("card_tiny_icon").height
|
||||
|
||||
|
||||
enabled: packageData.isCheckedByUltimaker
|
||||
visible: packageData.isCheckedByUltimaker
|
||||
|
||||
|
@ -100,7 +135,7 @@ Rectangle
|
|||
}
|
||||
}
|
||||
visible: parent.hovered
|
||||
targetPoint: Qt.point(0, Math.round(parent.y + parent.height / 2))
|
||||
targetPoint: Qt.point(0, Math.round(parent.y + parent.height / 4))
|
||||
}
|
||||
|
||||
Rectangle
|
||||
|
@ -182,22 +217,14 @@ Rectangle
|
|||
}
|
||||
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
|
||||
}
|
||||
id: shortDescription
|
||||
Layout.preferredWidth: parent.width
|
||||
Layout.fillHeight: true
|
||||
|
||||
Label
|
||||
{
|
||||
id: descriptionLabel
|
||||
|
@ -205,11 +232,13 @@ Rectangle
|
|||
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:
|
||||
{
|
||||
|
@ -233,24 +262,24 @@ Rectangle
|
|||
id: tripleDotLabel
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: descriptionLabel.lastLineWidth
|
||||
anchors.bottom: readMoreButton.bottom
|
||||
anchors.bottom: descriptionLabel.bottom
|
||||
|
||||
text: "… "
|
||||
font: descriptionLabel.font
|
||||
color: descriptionLabel.color
|
||||
visible: descriptionLabel.truncated
|
||||
visible: descriptionLabel.truncated && descriptionLabel.text !== ""
|
||||
}
|
||||
Cura.TertiaryButton
|
||||
{
|
||||
id: readMoreButton
|
||||
anchors.left: tripleDotLabel.right
|
||||
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
|
||||
visible: descriptionLabel.truncated && descriptionLabel.text !== ""
|
||||
enabled: visible
|
||||
leftPadding: UM.Theme.getSize("default_margin").width
|
||||
rightPadding: UM.Theme.getSize("wide_margin").width
|
||||
|
@ -261,24 +290,47 @@ Rectangle
|
|||
}
|
||||
}
|
||||
|
||||
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
|
||||
width: parent.width
|
||||
anchors
|
||||
{
|
||||
bottom: parent.bottom
|
||||
left: packageItem.right
|
||||
right: parent.right
|
||||
margins: UM.Theme.getSize("default_margin").height
|
||||
}
|
||||
Layout.preferredWidth: parent.width
|
||||
Layout.preferredHeight: childrenRect.height
|
||||
|
||||
spacing: UM.Theme.getSize("narrow_margin").width
|
||||
|
||||
Label
|
||||
{
|
||||
id: authorBy
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
Layout.alignment: Qt.AlignTop
|
||||
|
||||
text: catalog.i18nc("@label", "By")
|
||||
font: UM.Theme.getFont("default")
|
||||
|
@ -289,7 +341,7 @@ Rectangle
|
|||
{
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: authorBy.height
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
Layout.alignment: Qt.AlignTop
|
||||
|
||||
text: packageData.authorName
|
||||
textFont: UM.Theme.getFont("default_bold")
|
||||
|
@ -304,26 +356,252 @@ Rectangle
|
|||
|
||||
Cura.SecondaryButton
|
||||
{
|
||||
id: enableManageButton
|
||||
id: disableButton
|
||||
Layout.alignment: Qt.AlignTop
|
||||
text: packageData.enableManageButtonText
|
||||
visible: packageData.enableManageButtonVisible
|
||||
text: catalog.i18nc("@button", "Disable")
|
||||
visible: false // not functional right now, also only when unfolding and required
|
||||
}
|
||||
|
||||
Cura.SecondaryButton
|
||||
{
|
||||
id: installManageButton
|
||||
id: uninstallButton
|
||||
Layout.alignment: Qt.AlignTop
|
||||
text: packageData.installManageButtonText
|
||||
visible: packageData.installManageButtonVisible
|
||||
text: catalog.i18nc("@button", "Uninstall")
|
||||
visible: false // not functional right now, also only when unfolding and required
|
||||
}
|
||||
|
||||
Cura.PrimaryButton
|
||||
{
|
||||
id: updateManageButton
|
||||
id: installButton
|
||||
Layout.alignment: Qt.AlignTop
|
||||
text: catalog.i18nc("@button", "Update") // OR Download, if new!
|
||||
visible: packageData.updateManageButtonVisible
|
||||
visible: false // not functional right now, also only when unfolding and required
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column
|
||||
{
|
||||
id: extendedDescription
|
||||
width: parent.width
|
||||
|
||||
padding: UM.Theme.getSize("default_margin").width
|
||||
topPadding: 0
|
||||
spacing: UM.Theme.getSize("default_margin").height
|
||||
|
||||
Label
|
||||
{
|
||||
width: parent.width - parent.padding * 2
|
||||
|
||||
text: catalog.i18nc("@header", "Description")
|
||||
font: UM.Theme.getFont("medium_bold")
|
||||
color: UM.Theme.getColor("text")
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
Label
|
||||
{
|
||||
width: parent.width - parent.padding * 2
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue