MaterialsSyncDialog.qml 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757
  1. //Copyright (c) 2022 Ultimaker B.V.
  2. //Cura is released under the terms of the LGPLv3 or higher.
  3. import QtQuick 2.15
  4. import QtQuick.Controls 2.15
  5. import QtQuick.Dialogs
  6. import QtQuick.Layouts 1.15
  7. import QtQuick.Window 2.1
  8. import Cura 1.1 as Cura
  9. import UM 1.6 as UM
  10. UM.Window
  11. {
  12. id: materialsSyncDialog
  13. property variant catalog: UM.I18nCatalog { name: "cura" }
  14. title: catalog.i18nc("@title:window", "Sync materials with printers")
  15. minimumWidth: UM.Theme.getSize("modal_window_minimum").width
  16. minimumHeight: UM.Theme.getSize("modal_window_minimum").height
  17. width: minimumWidth
  18. height: minimumHeight
  19. modality: Qt.ApplicationModal
  20. color: UM.Theme.getColor("main_background")
  21. property variant syncModel
  22. property alias pageIndex: swipeView.currentIndex
  23. property alias syncStatusText: syncStatusLabel.text
  24. property bool hasExportedUsb: false
  25. SwipeView
  26. {
  27. id: swipeView
  28. anchors.fill: parent
  29. interactive: false
  30. Item
  31. {
  32. id: introPage
  33. ColumnLayout
  34. {
  35. spacing: UM.Theme.getSize("default_margin").height
  36. anchors.fill: parent
  37. anchors.margins: UM.Theme.getSize("default_margin").width
  38. UM.Label
  39. {
  40. text: catalog.i18nc("@title:header", "Sync materials with printers")
  41. font: UM.Theme.getFont("large_bold")
  42. Layout.fillWidth: true
  43. }
  44. UM.Label
  45. {
  46. text: catalog.i18nc("@text", "Following a few simple steps, you will be able to synchronize all your material profiles with your printers.")
  47. font: UM.Theme.getFont("medium")
  48. Layout.fillWidth: true
  49. }
  50. Image
  51. {
  52. Layout.fillWidth: true
  53. Layout.fillHeight: true
  54. source: UM.Theme.getImage("material_ecosystem")
  55. fillMode: Image.PreserveAspectFit
  56. sourceSize.width: width
  57. }
  58. Item
  59. {
  60. Layout.preferredHeight: childrenRect.height
  61. Layout.alignment: Qt.AlignBottom
  62. Layout.fillWidth: true
  63. Cura.TertiaryButton
  64. {
  65. text: catalog.i18nc("@button", "Why do I need to sync material profiles?")
  66. iconSource: UM.Theme.getIcon("LinkExternal")
  67. isIconOnRightSide: true
  68. onClicked: Qt.openUrlExternally("https://support.ultimaker.com/hc/en-us/articles/360013137919?utm_source=cura&utm_medium=software&utm_campaign=sync-material-printer-why")
  69. }
  70. Cura.PrimaryButton
  71. {
  72. anchors.right: parent.right
  73. text: catalog.i18nc("@button", "Start")
  74. onClicked:
  75. {
  76. if(Cura.API.account.isLoggedIn)
  77. {
  78. if(Cura.API.account.permissions.includes("digital-factory.printer.write"))
  79. {
  80. swipeView.currentIndex += 2; //Skip sign in page. Continue to sync via cloud.
  81. }
  82. else
  83. {
  84. //Logged in, but no permissions to start syncing. Direct them to USB.
  85. swipeView.currentIndex = removableDriveSyncPage.SwipeView.index;
  86. }
  87. }
  88. else
  89. {
  90. swipeView.currentIndex += 1;
  91. }
  92. }
  93. }
  94. }
  95. }
  96. }
  97. Item
  98. {
  99. id: signinPage
  100. // While this page is active, continue to the next page if the user logs in.
  101. Connections
  102. {
  103. target: Cura.API.account
  104. function onLoginStateChanged(is_logged_in)
  105. {
  106. if(is_logged_in && signinPage.SwipeView.isCurrentItem)
  107. {
  108. if(Cura.API.account.permissions.includes("digital-factory.printer.write"))
  109. {
  110. swipeView.currentIndex += 1;
  111. }
  112. else
  113. {
  114. //Logged in, but no permissions to start syncing. Direct them to USB.
  115. swipeView.currentIndex = removableDriveSyncPage.SwipeView.index;
  116. }
  117. }
  118. }
  119. }
  120. ColumnLayout
  121. {
  122. spacing: UM.Theme.getSize("default_margin").height
  123. anchors.fill: parent
  124. anchors.margins: UM.Theme.getSize("default_margin").width
  125. UM.Label
  126. {
  127. text: catalog.i18nc("@title:header", "Sign in")
  128. font: UM.Theme.getFont("large_bold")
  129. Layout.fillWidth: true
  130. }
  131. UM.Label
  132. {
  133. text: catalog.i18nc("@text", "To automatically sync the material profiles with all your printers connected to Digital Factory you need to be signed in in Cura.")
  134. font: UM.Theme.getFont("medium")
  135. Layout.fillWidth: true
  136. }
  137. Image
  138. {
  139. Layout.alignment: Qt.AlignCenter
  140. Layout.preferredWidth: parent.width / 2
  141. source: UM.Theme.getImage("first_run_ultimaker_cloud")
  142. Layout.fillHeight: true
  143. sourceSize.width: width
  144. fillMode: Image.PreserveAspectFit
  145. }
  146. Item
  147. {
  148. Layout.preferredHeight: childrenRect.height
  149. Layout.alignment: Qt.AlignBottom
  150. Layout.fillWidth: true
  151. Cura.SecondaryButton
  152. {
  153. anchors.left: parent.left
  154. text: catalog.i18nc("@button", "Sync materials with USB")
  155. onClicked: swipeView.currentIndex = removableDriveSyncPage.SwipeView.index
  156. }
  157. Cura.PrimaryButton
  158. {
  159. anchors.right: parent.right
  160. text: catalog.i18nc("@button", "Sign in")
  161. onClicked: Cura.API.account.login()
  162. }
  163. }
  164. }
  165. }
  166. Item
  167. {
  168. id: printerListPage
  169. ColumnLayout
  170. {
  171. spacing: UM.Theme.getSize("default_margin").height
  172. anchors.fill: parent
  173. anchors.margins: UM.Theme.getSize("default_margin").width
  174. visible: cloudPrinterList.count > 0
  175. Row
  176. {
  177. spacing: UM.Theme.getSize("default_margin").width
  178. states: [
  179. State
  180. {
  181. name: "idle"
  182. when: typeof syncModel === "undefined" || syncModel.exportUploadStatus == "idle" || syncModel.exportUploadStatus == "uploading"
  183. PropertyChanges { target: printerListHeader; text: catalog.i18nc("@title:header", "The following printers will receive the new material profiles:") }
  184. PropertyChanges { target: printerListHeaderIcon; status: UM.StatusIcon.Status.NEUTRAL; width: 0 }
  185. },
  186. State
  187. {
  188. name: "error"
  189. when: typeof syncModel !== "undefined" && syncModel.exportUploadStatus == "error"
  190. PropertyChanges { target: printerListHeader; text: catalog.i18nc("@title:header", "Something went wrong when sending the materials to the printers.") }
  191. PropertyChanges { target: printerListHeaderIcon; status: UM.StatusIcon.Status.ERROR }
  192. },
  193. State
  194. {
  195. name: "success"
  196. when: typeof syncModel !== "undefined" && syncModel.exportUploadStatus == "success"
  197. PropertyChanges { target: printerListHeader; text: catalog.i18nc("@title:header", "Material profiles successfully synced with the following printers:") }
  198. PropertyChanges { target: printerListHeaderIcon; status: UM.StatusIcon.Status.POSITIVE }
  199. }
  200. ]
  201. UM.StatusIcon
  202. {
  203. id: printerListHeaderIcon
  204. width: UM.Theme.getSize("section_icon").width
  205. height: UM.Theme.getSize("section_icon").height
  206. anchors.verticalCenter: parent.verticalCenter
  207. }
  208. UM.Label
  209. {
  210. id: printerListHeader
  211. anchors.verticalCenter: parent.verticalCenter
  212. //Text is always defined by the states above.
  213. font: UM.Theme.getFont("large_bold")
  214. }
  215. }
  216. Row
  217. {
  218. Layout.fillWidth: true
  219. Layout.preferredHeight: childrenRect.height
  220. UM.Label
  221. {
  222. id: syncStatusLabel
  223. anchors.left: parent.left
  224. elide: Text.ElideRight
  225. visible: text !== ""
  226. font: UM.Theme.getFont("medium")
  227. }
  228. Cura.TertiaryButton
  229. {
  230. id: troubleshootingLink
  231. anchors.right: parent.right
  232. text: catalog.i18nc("@button", "Troubleshooting")
  233. visible: typeof syncModel !== "undefined" && syncModel.exportUploadStatus == "error"
  234. iconSource: UM.Theme.getIcon("LinkExternal")
  235. onClicked: Qt.openUrlExternally("https://support.ultimaker.com/hc/en-us/articles/360012019239?utm_source=cura&utm_medium=software&utm_campaign=sync-material-wizard-troubleshoot-cloud-printer")
  236. }
  237. }
  238. ListView
  239. {
  240. id: printerList
  241. Layout.fillWidth: true
  242. Layout.fillHeight: true
  243. clip: true
  244. ScrollBar.vertical: UM.ScrollBar
  245. {
  246. id: printerListScrollBar
  247. }
  248. spacing: UM.Theme.getSize("default_margin").height
  249. model: cloudPrinterList
  250. delegate: Rectangle
  251. {
  252. id: delegateContainer
  253. color: "transparent"
  254. border.color: UM.Theme.getColor("lining")
  255. border.width: UM.Theme.getSize("default_lining").width
  256. width: printerList.width - printerListScrollBar.width
  257. height: UM.Theme.getSize("machine_selector_icon").height + 2 * UM.Theme.getSize("default_margin").height
  258. property string syncStatus:
  259. {
  260. var printer_id = model.metadata["host_guid"]
  261. if(syncModel.printerStatus[printer_id] === undefined) //No status information available. Could be added after we started syncing.
  262. {
  263. return "idle";
  264. }
  265. return syncModel.printerStatus[printer_id];
  266. }
  267. Cura.IconWithText
  268. {
  269. anchors
  270. {
  271. verticalCenter: parent.verticalCenter
  272. left: parent.left
  273. leftMargin: Math.round(parent.height - height) / 2 //Equal margin on the left as above and below.
  274. right: parent.right
  275. rightMargin: Math.round(parent.height - height) / 2
  276. }
  277. text: model.name
  278. font: UM.Theme.getFont("medium")
  279. source: UM.Theme.getIcon("Printer", "medium")
  280. iconColor: UM.Theme.getColor("machine_selector_printer_icon")
  281. iconSize: UM.Theme.getSize("machine_selector_icon").width
  282. //Printer status badge (always cloud, but whether it's online or offline).
  283. UM.ColorImage
  284. {
  285. width: UM.Theme.getSize("printer_status_icon").width
  286. height: UM.Theme.getSize("printer_status_icon").height
  287. anchors
  288. {
  289. bottom: parent.bottom
  290. bottomMargin: -Math.round(height / 6)
  291. left: parent.left
  292. leftMargin: parent.iconSize - Math.round(width * 5 / 6)
  293. }
  294. source: UM.Theme.getIcon("CloudBadge", "low")
  295. color: UM.Theme.getColor("primary")
  296. //Make a themeable circle in the background so we can change it in other themes.
  297. Rectangle
  298. {
  299. anchors.centerIn: parent
  300. width: parent.width - 1.5 //1.5 pixels smaller (at least sqrt(2), regardless of pixel scale) so that the circle doesn't show up behind the icon due to anti-aliasing.
  301. height: parent.height - 1.5
  302. radius: width / 2
  303. color: UM.Theme.getColor("connection_badge_background")
  304. z: parent.z - 1
  305. }
  306. }
  307. }
  308. UM.ColorImage
  309. {
  310. id: printerSpinner
  311. width: UM.Theme.getSize("section_icon").width
  312. height: width
  313. anchors.verticalCenter: parent.verticalCenter
  314. anchors.right: parent.right
  315. anchors.rightMargin: Math.round((parent.height - height) / 2) //Same margin on the right as above and below.
  316. visible: delegateContainer.syncStatus === "uploading"
  317. source: UM.Theme.getIcon("ArrowDoubleCircleRight")
  318. color: UM.Theme.getColor("primary")
  319. RotationAnimator
  320. {
  321. target: printerSpinner
  322. from: 0
  323. to: 360
  324. duration: 1000
  325. loops: Animation.Infinite
  326. running: true
  327. }
  328. }
  329. UM.StatusIcon
  330. {
  331. width: UM.Theme.getSize("section_icon").width
  332. height: width
  333. anchors.verticalCenter: parent.verticalCenter
  334. anchors.right: parent.right
  335. anchors.rightMargin: Math.round((parent.height - height) / 2) //Same margin on the right as above and below.
  336. visible: delegateContainer.syncStatus === "failed" || delegateContainer.syncStatus === "success"
  337. status: delegateContainer.syncStatus === "success" ? UM.StatusIcon.Status.POSITIVE : UM.StatusIcon.Status.ERROR
  338. }
  339. }
  340. footer: Item
  341. {
  342. width: printerList.width - printerListScrollBar.width
  343. height: childrenRect.height + UM.Theme.getSize("default_margin").height
  344. visible: includeOfflinePrinterList.count - cloudPrinterList.count > 0 && typeof syncModel !== "undefined" && syncModel.exportUploadStatus === "idle"
  345. Rectangle
  346. {
  347. anchors.top: parent.top
  348. anchors.left: parent.left
  349. anchors.right: parent.right
  350. border.color: UM.Theme.getColor("lining")
  351. border.width: UM.Theme.getSize("default_lining").width
  352. anchors.topMargin: UM.Theme.getSize("default_margin").height
  353. height: childrenRect.height + 2 * UM.Theme.getSize("thick_margin").height
  354. color: "transparent"
  355. GridLayout
  356. {
  357. columns: 3
  358. rows: 2
  359. anchors.top: parent.top
  360. anchors.left: parent.left
  361. anchors.right: parent.right
  362. anchors.leftMargin: UM.Theme.getSize("thick_margin").width
  363. anchors.rightMargin: UM.Theme.getSize("thick_margin").width
  364. anchors.topMargin: UM.Theme.getSize("thick_margin").height
  365. anchors.bottomMargin: UM.Theme.getSize("thick_margin").height
  366. columnSpacing: UM.Theme.getSize("default_margin").width
  367. rowSpacing: UM.Theme.getSize("default_margin").height
  368. UM.StatusIcon
  369. {
  370. Layout.preferredWidth: UM.Theme.getSize("section_icon").width
  371. Layout.preferredHeight: UM.Theme.getSize("section_icon").height
  372. status: UM.StatusIcon.Status.WARNING
  373. }
  374. UM.Label
  375. {
  376. Layout.fillWidth: true
  377. Layout.alignment: Qt.AlignVCenter
  378. text: catalog.i18nc("@text Asking the user whether printers are missing in a list.", "Printers missing?")
  379. + "\n"
  380. + catalog.i18nc("@text", "Make sure all your printers are turned ON and connected to Digital Factory.")
  381. font: UM.Theme.getFont("medium")
  382. elide: Text.ElideRight
  383. }
  384. Cura.SecondaryButton
  385. {
  386. id: refreshListButton
  387. Layout.alignment: Qt.AlignVCenter
  388. text: catalog.i18nc("@button", "Refresh List")
  389. iconSource: UM.Theme.getIcon("ArrowDoubleCircleRight")
  390. onClicked: Cura.API.account.sync(true)
  391. }
  392. Cura.TertiaryButton
  393. {
  394. id: printerListTroubleshooting
  395. Layout.column: 1
  396. Layout.row: 1
  397. Layout.fillWidth: true
  398. leftPadding: 0
  399. text: catalog.i18nc("@button", "Troubleshooting")
  400. iconSource: UM.Theme.getIcon("LinkExternal")
  401. onClicked: Qt.openUrlExternally("https://support.ultimaker.com/hc/en-us/articles/360012019239?utm_source=cura&utm_medium=software&utm_campaign=sync-material-wizard-troubleshoot-cloud-printer")
  402. }
  403. }
  404. }
  405. }
  406. }
  407. Item
  408. {
  409. Layout.fillWidth: true
  410. Layout.preferredHeight: childrenRect.height
  411. Layout.alignment: Qt.AlignBottom
  412. Cura.SecondaryButton
  413. {
  414. anchors.left: parent.left
  415. text: catalog.i18nc("@button", "Sync materials with USB")
  416. onClicked: swipeView.currentIndex = removableDriveSyncPage.SwipeView.index
  417. }
  418. Cura.PrimaryButton
  419. {
  420. id: syncButton
  421. anchors.right: parent.right
  422. text:
  423. {
  424. if(typeof syncModel !== "undefined" && syncModel.exportUploadStatus == "error")
  425. {
  426. return catalog.i18nc("@button", "Try again");
  427. }
  428. if(typeof syncModel !== "undefined" && syncModel.exportUploadStatus == "success")
  429. {
  430. return catalog.i18nc("@button", "Done");
  431. }
  432. return catalog.i18nc("@button", "Sync");
  433. }
  434. onClicked:
  435. {
  436. if(typeof syncModel !== "undefined" && syncModel.exportUploadStatus == "success")
  437. {
  438. materialsSyncDialog.close();
  439. }
  440. else
  441. {
  442. syncModel.exportUpload();
  443. }
  444. }
  445. visible:
  446. {
  447. if(!syncModel) //When the dialog is created, this is not set yet.
  448. {
  449. return true;
  450. }
  451. return syncModel.exportUploadStatus != "uploading";
  452. }
  453. }
  454. Item
  455. {
  456. anchors.right: parent.right
  457. width: childrenRect.width
  458. height: syncButton.height
  459. visible: !syncButton.visible
  460. UM.ColorImage
  461. {
  462. id: syncingIcon
  463. height: UM.Theme.getSize("action_button_icon").height
  464. width: height
  465. anchors.verticalCenter: syncingLabel.verticalCenter
  466. source: UM.Theme.getIcon("ArrowDoubleCircleRight")
  467. color: UM.Theme.getColor("primary")
  468. RotationAnimator
  469. {
  470. target: syncingIcon
  471. from: 0
  472. to: 360
  473. duration: 1000
  474. loops: Animation.Infinite
  475. running: true
  476. }
  477. }
  478. UM.Label
  479. {
  480. id: syncingLabel
  481. anchors.left: syncingIcon.right
  482. anchors.leftMargin: UM.Theme.getSize("narrow_margin").width
  483. text: catalog.i18nc("@button", "Syncing")
  484. color: UM.Theme.getColor("primary")
  485. font: UM.Theme.getFont("medium")
  486. }
  487. }
  488. }
  489. }
  490. // Placeholder for when the user has no cloud printers.
  491. ColumnLayout
  492. {
  493. spacing: UM.Theme.getSize("default_margin").height
  494. anchors.fill: parent
  495. anchors.margins: UM.Theme.getSize("default_margin").width
  496. visible: cloudPrinterList.count == 0
  497. UM.Label
  498. {
  499. text: catalog.i18nc("@title:header", "No printers found")
  500. font: UM.Theme.getFont("large_bold")
  501. Layout.fillWidth: true
  502. }
  503. Item
  504. {
  505. Layout.fillWidth: true
  506. Layout.fillHeight: true
  507. Image
  508. {
  509. anchors.fill: parent
  510. source: UM.Theme.getImage("3d_printer_faded")
  511. sourceSize.width: width
  512. fillMode: Image.PreserveAspectFit
  513. }
  514. }
  515. UM.Label
  516. {
  517. text: catalog.i18nc("@text", "It seems like you don't have any compatible printers connected to Digital Factory. Make sure your printer is connected and it's running the latest firmware.")
  518. Layout.fillWidth: true
  519. horizontalAlignment: Text.AlignHCenter
  520. }
  521. Item
  522. {
  523. Layout.fillWidth: true
  524. Layout.preferredHeight: parent.height / 4
  525. Cura.TertiaryButton
  526. {
  527. text: catalog.i18nc("@button", "Learn how to connect your printer to Digital Factory")
  528. iconSource: UM.Theme.getIcon("LinkExternal")
  529. onClicked: Qt.openUrlExternally("https://support.ultimaker.com/hc/en-us/articles/360012019239?utm_source=cura&utm_medium=software&utm_campaign=sync-material-wizard-add-cloud-printer")
  530. anchors.horizontalCenter: parent.horizontalCenter
  531. maximumWidth: parent.width
  532. }
  533. }
  534. Item
  535. {
  536. Layout.preferredHeight: childrenRect.height
  537. Layout.alignment: Qt.AlignBottom
  538. Layout.fillWidth: true
  539. Cura.SecondaryButton
  540. {
  541. anchors.left: parent.left
  542. text: catalog.i18nc("@button", "Sync materials with USB")
  543. onClicked: swipeView.currentIndex = removableDriveSyncPage.SwipeView.index
  544. }
  545. RowLayout
  546. {
  547. anchors.right: parent.right
  548. spacing: UM.Theme.getSize("default_margin").width
  549. Cura.SecondaryButton
  550. {
  551. text: catalog.i18nc("@button", "Refresh")
  552. iconSource: UM.Theme.getIcon("ArrowDoubleCircleRight")
  553. outlineColor: "transparent"
  554. onClicked: Cura.API.account.sync(true)
  555. }
  556. Cura.PrimaryButton
  557. {
  558. id: disabledSyncButton
  559. text: catalog.i18nc("@button", "Sync")
  560. enabled: false // If there are no printers, always disable this button.
  561. }
  562. }
  563. }
  564. }
  565. }
  566. Item
  567. {
  568. id: removableDriveSyncPage
  569. ColumnLayout
  570. {
  571. spacing: UM.Theme.getSize("default_margin").height
  572. anchors.fill: parent
  573. anchors.margins: UM.Theme.getSize("default_margin").width
  574. UM.Label
  575. {
  576. text: catalog.i18nc("@title:header", "Sync material profiles via USB")
  577. font: UM.Theme.getFont("large_bold")
  578. Layout.fillWidth: true
  579. }
  580. UM.Label
  581. {
  582. text: catalog.i18nc("@text In the UI this is followed by a list of steps the user needs to take.", "Follow the following steps to load the new material profiles to your printer.")
  583. font: UM.Theme.getFont("medium")
  584. Layout.fillWidth: true
  585. }
  586. RowLayout
  587. {
  588. Layout.fillWidth: true
  589. Layout.fillHeight: true
  590. spacing: UM.Theme.getSize("default_margin").width
  591. Item
  592. {
  593. Layout.preferredWidth: parent.width / 3
  594. Layout.fillHeight: true
  595. Image
  596. {
  597. anchors.fill: parent
  598. source: UM.Theme.getImage("insert_usb")
  599. verticalAlignment: Image.AlignVCenter
  600. horizontalAlignment: Image.AlignHCenter
  601. fillMode: Image.PreserveAspectFit
  602. sourceSize.width: width
  603. }
  604. }
  605. UM.Label
  606. {
  607. Layout.alignment: Qt.AlignCenter
  608. Layout.fillWidth: true
  609. text: "1. " + catalog.i18nc("@text", "Click the export material archive button.")
  610. + "\n2. " + catalog.i18nc("@text", "Save the .umm file on a USB stick.")
  611. + "\n3. " + catalog.i18nc("@text", "Insert the USB stick into your printer and launch the procedure to load new material profiles.")
  612. font: UM.Theme.getFont("medium")
  613. }
  614. }
  615. Cura.TertiaryButton
  616. {
  617. Layout.fillWidth: true
  618. text: catalog.i18nc("@button", "How to load new material profiles to my printer")
  619. iconSource: UM.Theme.getIcon("LinkExternal")
  620. onClicked: Qt.openUrlExternally("https://support.ultimaker.com/hc/en-us/articles/4403319801106/?utm_source=cura&utm_medium=software&utm_campaign=add-material-profiles-via-usb")
  621. }
  622. Item
  623. {
  624. Layout.preferredHeight: childrenRect.height
  625. Layout.alignment: Qt.AlignBottom
  626. Layout.fillWidth: true
  627. Cura.SecondaryButton
  628. {
  629. anchors.left: parent.left
  630. text: catalog.i18nc("@button", "Back")
  631. onClicked: swipeView.currentIndex = 0 //Reset to first page.
  632. }
  633. Cura.PrimaryButton
  634. {
  635. id: exportUsbButton
  636. anchors.right: parent.right
  637. property bool hasExported: false
  638. text: materialsSyncDialog.hasExportedUsb ? catalog.i18nc("@button", "Done") : catalog.i18nc("@button", "Export material archive")
  639. onClicked:
  640. {
  641. if(!materialsSyncDialog.hasExportedUsb)
  642. {
  643. exportUsbDialog.currentFolder = `${syncModel.getPreferredExportAllPath()}/materials.umm`;
  644. exportUsbDialog.open();
  645. }
  646. else
  647. {
  648. materialsSyncDialog.close();
  649. }
  650. }
  651. }
  652. }
  653. }
  654. }
  655. }
  656. property variant cloudPrinterList: Cura.GlobalStacksModel
  657. {
  658. filterConnectionType: 3 //Only show cloud connections.
  659. filterOnlineOnly: true //Only show printers that are online.
  660. filterCapabilities: ["import_material"] //Only show printers that can receive the material profiles.
  661. }
  662. property variant includeOfflinePrinterList: Cura.GlobalStacksModel
  663. {
  664. //In order to show a refresh button only when there are offline cloud printers, we need to know if there are any offline printers.
  665. //A global stacks model without the filter for online-only printers allows this.
  666. filterConnectionType: 3 //Still only show cloud connections.
  667. }
  668. property variant exportUsbDialog: FileDialog
  669. {
  670. title: catalog.i18nc("@title:window", "Export All Materials")
  671. nameFilters: ["Material archives (*.umm)", "All files (*)"]
  672. fileMode: FileDialog.SaveFile
  673. onAccepted:
  674. {
  675. syncModel.exportAll(selectedFile);
  676. CuraApplication.setDefaultPath("dialog_material_path", folder);
  677. materialsSyncDialog.hasExportedUsb = true;
  678. }
  679. }
  680. }