MaterialsSyncDialog.qml 35 KB

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