mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-08-09 06:45:09 -06:00
Merge branch 'CURA-8014_welcome_pages_attract_mode' of github.com:Ultimaker/Cura
This commit is contained in:
commit
2e88a3463c
12 changed files with 312 additions and 32 deletions
|
@ -239,9 +239,6 @@ class WelcomePagesModel(ListModel):
|
|||
{"id": "user_agreement",
|
||||
"page_url": self._getBuiltinWelcomePagePath("UserAgreementContent.qml"),
|
||||
},
|
||||
{"id": "whats_new",
|
||||
"page_url": self._getBuiltinWelcomePagePath("WhatsNewContent.qml"),
|
||||
},
|
||||
{"id": "data_collections",
|
||||
"page_url": self._getBuiltinWelcomePagePath("DataCollectionsContent.qml"),
|
||||
},
|
||||
|
@ -259,13 +256,21 @@ class WelcomePagesModel(ListModel):
|
|||
},
|
||||
{"id": "add_cloud_printers",
|
||||
"page_url": self._getBuiltinWelcomePagePath("AddCloudPrintersView.qml"),
|
||||
"is_final_page": True, # If we end up in this page, the next button will close the dialog
|
||||
"next_page_button_text": self._catalog.i18nc("@action:button", "Finish"),
|
||||
"next_page_button_text": self._catalog.i18nc("@action:button", "Next"),
|
||||
"next_page_id": "whats_new",
|
||||
},
|
||||
{"id": "machine_actions",
|
||||
"page_url": self._getBuiltinWelcomePagePath("FirstStartMachineActionsContent.qml"),
|
||||
"should_show_function": self.shouldShowMachineActions,
|
||||
},
|
||||
{"id": "whats_new",
|
||||
"page_url": self._getBuiltinWelcomePagePath("WhatsNewContent.qml"),
|
||||
"next_page_button_text": self._catalog.i18nc("@action:button", "Skip"),
|
||||
},
|
||||
{"id": "changelog",
|
||||
"page_url": self._getBuiltinWelcomePagePath("ChangelogContent.qml"),
|
||||
"next_page_button_text": self._catalog.i18nc("@action:button", "Finish"),
|
||||
},
|
||||
]
|
||||
|
||||
pages_to_show = all_pages_list
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
# Copyright (c) 2019 Ultimaker B.V.
|
||||
# Copyright (c) 2021 Ultimaker B.V.
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
from .WelcomePagesModel import WelcomePagesModel
|
||||
|
||||
import os
|
||||
from typing import Optional, Dict, List, Tuple
|
||||
from PyQt5.QtCore import pyqtProperty, pyqtSlot
|
||||
from UM.Logger import Logger
|
||||
from UM.Resources import Resources
|
||||
|
||||
#
|
||||
# This Qt ListModel is more or less the same the WelcomePagesModel, except that this model is only for showing the
|
||||
|
@ -10,13 +14,84 @@ from .WelcomePagesModel import WelcomePagesModel
|
|||
#
|
||||
class WhatsNewPagesModel(WelcomePagesModel):
|
||||
|
||||
image_formats = [".png", ".jpg", ".jpeg", ".gif", ".svg"]
|
||||
text_formats = [".txt", ".htm", ".html"]
|
||||
image_key = "image"
|
||||
text_key = "text"
|
||||
|
||||
@staticmethod
|
||||
def _collectOrdinalFiles(resource_type: int, include: List[str]) -> Tuple[Dict[int, str], int]:
|
||||
result = {} #type: Dict[int, str]
|
||||
highest = -1
|
||||
try:
|
||||
folder_path = Resources.getPath(resource_type, "whats_new")
|
||||
for _, _, files in os.walk(folder_path):
|
||||
for filename in files:
|
||||
basename = os.path.basename(filename)
|
||||
base, ext = os.path.splitext(basename)
|
||||
if ext not in include or not base.isdigit():
|
||||
continue
|
||||
page_no = int(base)
|
||||
highest = max(highest, page_no)
|
||||
result[page_no] = os.path.join(folder_path, filename)
|
||||
except FileNotFoundError:
|
||||
Logger.logException("w", "Could not find 'whats_new' folder for resource-type {0}".format(resource_type))
|
||||
return result, highest
|
||||
|
||||
@staticmethod
|
||||
def _loadText(filename: str) -> str:
|
||||
result = ""
|
||||
try:
|
||||
with open(filename, "r", encoding="utf-8") as file:
|
||||
result = file.read()
|
||||
except OSError:
|
||||
Logger.logException("w", "Could not open {0}".format(filename))
|
||||
return result
|
||||
|
||||
def initialize(self) -> None:
|
||||
self._pages = []
|
||||
self._pages.append({"id": "whats_new",
|
||||
"page_url": self._getBuiltinWelcomePagePath("WhatsNewContent.qml"),
|
||||
"next_page_button_text": self._catalog.i18nc("@action:button", "Skip"),
|
||||
"next_page_id": "changelog"
|
||||
})
|
||||
self._pages.append({"id": "changelog",
|
||||
"page_url": self._getBuiltinWelcomePagePath("ChangelogContent.qml"),
|
||||
"next_page_button_text": self._catalog.i18nc("@action:button", "Close"),
|
||||
})
|
||||
self.setItems(self._pages)
|
||||
|
||||
images, max_image = WhatsNewPagesModel._collectOrdinalFiles(Resources.Images, WhatsNewPagesModel.image_formats)
|
||||
texts, max_text = WhatsNewPagesModel._collectOrdinalFiles(Resources.Texts, WhatsNewPagesModel.text_formats)
|
||||
highest = max(max_image, max_text)
|
||||
|
||||
self._subpages = [] #type: List[Dict[str, Optional[str]]]
|
||||
for n in range(0, highest + 1):
|
||||
self._subpages.append({
|
||||
WhatsNewPagesModel.image_key: None if n not in images else images[n],
|
||||
WhatsNewPagesModel.text_key: None if n not in texts else self._loadText(texts[n])
|
||||
})
|
||||
if len(self._subpages) == 0:
|
||||
self._subpages.append({WhatsNewPagesModel.text_key: "~ There Is Nothing New Under The Sun ~"})
|
||||
|
||||
def _getSubpageItem(self, page: int, item: str) -> Optional[str]:
|
||||
if 0 <= page < self.subpageCount and item in self._subpages[page]:
|
||||
return self._subpages[page][item]
|
||||
else:
|
||||
return None
|
||||
|
||||
@pyqtProperty(int, constant = True)
|
||||
def subpageCount(self) -> int:
|
||||
return len(self._subpages)
|
||||
|
||||
@pyqtSlot(int, result = str)
|
||||
def getSubpageImageSource(self, page: int) -> str:
|
||||
result = self._getSubpageItem(page, WhatsNewPagesModel.image_key)
|
||||
return "file:///" + (result if result else Resources.getPath(Resources.Images, "cura-icon.png"))
|
||||
|
||||
@pyqtSlot(int, result = str)
|
||||
def getSubpageText(self, page: int) -> str:
|
||||
result = self._getSubpageItem(page, WhatsNewPagesModel.text_key)
|
||||
return result if result else "* * *"
|
||||
|
||||
__all__ = ["WhatsNewPagesModel"]
|
||||
|
|
BIN
resources/images/whats_new/0.png
Normal file
BIN
resources/images/whats_new/0.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
BIN
resources/images/whats_new/1.png
Normal file
BIN
resources/images/whats_new/1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2 KiB |
BIN
resources/images/whats_new/2.png
Normal file
BIN
resources/images/whats_new/2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
|
@ -215,7 +215,7 @@ Item
|
|||
id: finishButton
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
text: catalog.i18nc("@button", "Finish")
|
||||
text: base.currentItem.next_page_button_text
|
||||
onClicked:
|
||||
{
|
||||
discoveredCloudPrintersModel.clear()
|
||||
|
|
59
resources/qml/WelcomePages/ChangelogContent.qml
Normal file
59
resources/qml/WelcomePages/ChangelogContent.qml
Normal file
|
@ -0,0 +1,59 @@
|
|||
// Copyright (c) 2021 Ultimaker B.V.
|
||||
// Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import QtQuick 2.10
|
||||
import QtQuick.Controls 2.3
|
||||
|
||||
import UM 1.3 as UM
|
||||
import Cura 1.1 as Cura
|
||||
|
||||
|
||||
//
|
||||
// This component contains the content for the "What's new in Ultimaker Cura" page of the welcome on-boarding process.
|
||||
//
|
||||
Item
|
||||
{
|
||||
UM.I18nCatalog { id: catalog; name: "cura" }
|
||||
|
||||
Label
|
||||
{
|
||||
id: titleLabel
|
||||
anchors.top: parent.top
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: catalog.i18nc("@label", "Release Notes / 'Changelog'")
|
||||
color: UM.Theme.getColor("primary_button")
|
||||
font: UM.Theme.getFont("huge")
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
|
||||
Cura.ScrollableTextArea
|
||||
{
|
||||
id: changelogTextArea
|
||||
|
||||
anchors.top: titleLabel.bottom
|
||||
anchors.bottom: getStartedButton.top
|
||||
anchors.topMargin: UM.Theme.getSize("wide_margin").height
|
||||
anchors.bottomMargin: UM.Theme.getSize("wide_margin").height
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
|
||||
|
||||
textArea.text: CuraApplication.getTextManager().getChangeLogText()
|
||||
textArea.textFormat: Text.RichText
|
||||
textArea.wrapMode: Text.WordWrap
|
||||
textArea.readOnly: true
|
||||
textArea.font: UM.Theme.getFont("medium")
|
||||
textArea.onLinkActivated: Qt.openUrlExternally(link)
|
||||
}
|
||||
|
||||
Cura.PrimaryButton
|
||||
{
|
||||
id: getStartedButton
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
text: base.currentItem.next_page_button_text
|
||||
onClicked: base.showNextPage()
|
||||
}
|
||||
}
|
|
@ -1,8 +1,9 @@
|
|||
// Copyright (c) 2019 Ultimaker B.V.
|
||||
// Copyright (c) 2021 Ultimaker B.V.
|
||||
// Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import QtQuick 2.10
|
||||
import QtQuick.Controls 2.3
|
||||
import QtQuick.Layouts 1.3
|
||||
|
||||
import UM 1.3 as UM
|
||||
import Cura 1.1 as Cura
|
||||
|
@ -10,9 +11,12 @@ import Cura 1.1 as Cura
|
|||
|
||||
//
|
||||
// This component contains the content for the "What's new in Ultimaker Cura" page of the welcome on-boarding process.
|
||||
// Previously this was just the changelog, but now it will just have the larger stories, the changelog has its own page.
|
||||
//
|
||||
Item
|
||||
{
|
||||
property var manager: CuraApplication.getWhatsNewPagesModel()
|
||||
|
||||
UM.I18nCatalog { id: catalog; name: "cura" }
|
||||
|
||||
Label
|
||||
|
@ -21,39 +25,164 @@ Item
|
|||
anchors.top: parent.top
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: catalog.i18nc("@label", "What's new in Ultimaker Cura")
|
||||
text: catalog.i18nc("@label", "What's New")
|
||||
color: UM.Theme.getColor("primary_button")
|
||||
font: UM.Theme.getFont("huge")
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
|
||||
Cura.ScrollableTextArea
|
||||
Item
|
||||
{
|
||||
id: whatsNewTextArea
|
||||
|
||||
id: topSpacer
|
||||
anchors.top: titleLabel.bottom
|
||||
anchors.bottom: getStartedButton.top
|
||||
anchors.topMargin: UM.Theme.getSize("wide_margin").height
|
||||
anchors.bottomMargin: UM.Theme.getSize("wide_margin").height
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
|
||||
|
||||
textArea.text: CuraApplication.getTextManager().getChangeLogText()
|
||||
textArea.textFormat: Text.RichText
|
||||
textArea.wrapMode: Text.WordWrap
|
||||
textArea.readOnly: true
|
||||
textArea.font: UM.Theme.getFont("medium")
|
||||
textArea.onLinkActivated: Qt.openUrlExternally(link)
|
||||
height: UM.Theme.getSize("default_margin").height
|
||||
width: UM.Theme.getSize("default_margin").width
|
||||
}
|
||||
|
||||
Cura.PrimaryButton
|
||||
Rectangle
|
||||
{
|
||||
id: getStartedButton
|
||||
anchors.right: parent.right
|
||||
anchors
|
||||
{
|
||||
top: topSpacer.bottom
|
||||
bottom: whatsNewDots.top
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
margins: UM.Theme.getSize("default_margin").width * 2
|
||||
}
|
||||
|
||||
color: UM.Theme.getColor("viewport_overlay")
|
||||
|
||||
StackLayout
|
||||
{
|
||||
id: whatsNewViewport
|
||||
|
||||
anchors
|
||||
{
|
||||
top: parent.top
|
||||
topMargin: UM.Theme.getSize("default_margin").width
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
height: parent.height
|
||||
width: parent.width
|
||||
|
||||
currentIndex: whatsNewDots.currentIndex
|
||||
|
||||
Repeater
|
||||
{
|
||||
anchors
|
||||
{
|
||||
top: parent.top
|
||||
topMargin: UM.Theme.getSize("default_margin").width / 2
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
model: manager.subpageCount
|
||||
|
||||
Rectangle
|
||||
{
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
color: UM.Theme.getColor("viewport_overlay")
|
||||
|
||||
Image
|
||||
{
|
||||
id: subpageImage
|
||||
|
||||
anchors
|
||||
{
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
top: parent.top
|
||||
topMargin: UM.Theme.getSize("default_margin").width
|
||||
}
|
||||
width: parent.width - (UM.Theme.getSize("default_margin").width * 2)
|
||||
height: (parent.height - UM.Theme.getSize("default_margin").height) * 0.75
|
||||
fillMode: Image.PreserveAspectFit
|
||||
|
||||
source: manager.getSubpageImageSource(index)
|
||||
}
|
||||
|
||||
Cura.ScrollableTextArea
|
||||
{
|
||||
id: subpageText
|
||||
|
||||
anchors
|
||||
{
|
||||
top: subpageImage.bottom
|
||||
bottom: parent.bottom
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
width: parent.width - (UM.Theme.getSize("default_margin").width * 2)
|
||||
|
||||
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
|
||||
|
||||
back_color: UM.Theme.getColor("viewport_overlay")
|
||||
do_borders: false
|
||||
|
||||
textArea.wrapMode: TextEdit.Wrap
|
||||
textArea.text: manager.getSubpageText(index)
|
||||
textArea.textFormat: Text.RichText
|
||||
textArea.readOnly: true
|
||||
textArea.font: UM.Theme.getFont("medium")
|
||||
textArea.onLinkActivated: Qt.openUrlExternally(link)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PageIndicator
|
||||
{
|
||||
id: whatsNewDots
|
||||
|
||||
currentIndex: whatsNewViewport.currentIndex
|
||||
count: whatsNewViewport.count
|
||||
interactive: true
|
||||
|
||||
anchors
|
||||
{
|
||||
bottom: bottomSpacer.top
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
delegate:
|
||||
Rectangle
|
||||
{
|
||||
width: UM.Theme.getSize("thin_margin").width
|
||||
height: UM.Theme.getSize("thin_margin").height
|
||||
|
||||
radius: width / 2
|
||||
color:
|
||||
index === whatsNewViewport.currentIndex ?
|
||||
UM.Theme.getColor("primary") :
|
||||
UM.Theme.getColor("secondary_button_shadow")
|
||||
}
|
||||
}
|
||||
|
||||
Item
|
||||
{
|
||||
id: bottomSpacer
|
||||
anchors.bottom: whatsNewNextButton.top
|
||||
height: UM.Theme.getSize("default_margin").height / 2
|
||||
width: UM.Theme.getSize("default_margin").width / 2
|
||||
}
|
||||
|
||||
Cura.TertiaryButton
|
||||
{
|
||||
id: whatsNewNextButton
|
||||
anchors.left: parent.left
|
||||
anchors.bottom: parent.bottom
|
||||
text: base.currentItem.next_page_button_text
|
||||
onClicked: base.showNextPage()
|
||||
}
|
||||
|
||||
Cura.PrimaryButton
|
||||
{
|
||||
id: whatsNewSubpageButton
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
text: catalog.i18nc("@button", "Next")
|
||||
onClicked:
|
||||
whatsNewDots.currentIndex === (whatsNewDots.count - 1) ?
|
||||
base.showNextPage() :
|
||||
++whatsNewDots.currentIndex
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,13 +15,16 @@ ScrollView
|
|||
{
|
||||
property alias textArea: _textArea
|
||||
|
||||
property var back_color: UM.Theme.getColor("main_background")
|
||||
property var do_borders: true
|
||||
|
||||
clip: true
|
||||
|
||||
background: Rectangle // Border
|
||||
{
|
||||
color: UM.Theme.getColor("main_background")
|
||||
color: back_color
|
||||
border.color: UM.Theme.getColor("thick_lining")
|
||||
border.width: UM.Theme.getSize("default_lining").width
|
||||
border.width: do_borders ? UM.Theme.getSize("default_lining").width : 0
|
||||
}
|
||||
|
||||
TextArea
|
||||
|
|
5
resources/texts/whats_new/0.html
Normal file
5
resources/texts/whats_new/0.html
Normal file
|
@ -0,0 +1,5 @@
|
|||
<h4>Hot New Feature (1/2)</h4>
|
||||
<p>
|
||||
Lorem ipsum et cetera ad infinitum dolce et gabana carpe diem. <br/>
|
||||
Link to <a href="https://example.com">EXAMPLE</a>.
|
||||
</p>
|
2
resources/texts/whats_new/1.html
Normal file
2
resources/texts/whats_new/1.html
Normal file
|
@ -0,0 +1,2 @@
|
|||
<h4>Hot New Feature (2/2)</h4>
|
||||
<p>Pa's wijze lynx bezag vroom het fikse aquaduct.</p>
|
2
resources/texts/whats_new/2.html
Normal file
2
resources/texts/whats_new/2.html
Normal file
|
@ -0,0 +1,2 @@
|
|||
<h4>The other thing we wanted to tell you!</h4>
|
||||
<p>The quick brown fox jumps over the lazy dog.</p>
|
Loading…
Add table
Add a link
Reference in a new issue