MaterialsSyncDialog.qml 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
  1. //Copyright (c) 2021 Ultimaker B.V.
  2. //Cura is released under the terms of the LGPLv3 or higher.
  3. import QtQuick 2.1
  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.2 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 materialManagementModel
  21. property alias pageIndex: swipeView.currentIndex
  22. SwipeView
  23. {
  24. id: swipeView
  25. anchors.fill: parent
  26. interactive: false
  27. Rectangle
  28. {
  29. id: introPage
  30. color: UM.Theme.getColor("main_background")
  31. Column
  32. {
  33. spacing: UM.Theme.getSize("default_margin").height
  34. anchors.fill: parent
  35. anchors.margins: UM.Theme.getSize("default_margin").width
  36. Label
  37. {
  38. text: catalog.i18nc("@title:header", "Sync materials with printers")
  39. font: UM.Theme.getFont("large_bold")
  40. color: UM.Theme.getColor("text")
  41. }
  42. Label
  43. {
  44. text: catalog.i18nc("@text", "Following a few simple steps, you will be able to synchronize all your material profiles with your printers.")
  45. font: UM.Theme.getFont("medium")
  46. color: UM.Theme.getColor("text")
  47. wrapMode: Text.Wrap
  48. width: parent.width
  49. }
  50. Image
  51. {
  52. source: UM.Theme.getImage("material_ecosystem")
  53. width: parent.width
  54. sourceSize.width: width
  55. }
  56. }
  57. Cura.PrimaryButton
  58. {
  59. id: startButton
  60. anchors
  61. {
  62. right: parent.right
  63. rightMargin: UM.Theme.getSize("default_margin").width
  64. bottom: parent.bottom
  65. bottomMargin: UM.Theme.getSize("default_margin").height
  66. }
  67. text: catalog.i18nc("@button", "Start")
  68. onClicked:
  69. {
  70. if(Cura.API.account.isLoggedIn)
  71. {
  72. swipeView.currentIndex += 2; //Skip sign in page.
  73. }
  74. else
  75. {
  76. swipeView.currentIndex += 1;
  77. }
  78. }
  79. }
  80. Cura.TertiaryButton
  81. {
  82. anchors
  83. {
  84. left: parent.left
  85. leftMargin: UM.Theme.getSize("default_margin").width
  86. verticalCenter: startButton.verticalCenter
  87. }
  88. text: catalog.i18nc("@button", "Why do I need to sync material profiles?")
  89. iconSource: UM.Theme.getIcon("LinkExternal")
  90. isIconOnRightSide: true
  91. onClicked: Qt.openUrlExternally("https://support.ultimaker.com/hc/en-us/articles/360013137919?utm_source=cura&utm_medium=software&utm_campaign=sync-material-printer-why")
  92. }
  93. }
  94. Rectangle
  95. {
  96. id: signinPage
  97. color: UM.Theme.getColor("main_background")
  98. Connections //While this page is active, continue to the next page if the user logs in.
  99. {
  100. target: Cura.API.account
  101. function onLoginStateChanged(is_logged_in)
  102. {
  103. if(is_logged_in && signinPage.SwipeView.isCurrentItem)
  104. {
  105. swipeView.currentIndex += 1;
  106. }
  107. }
  108. }
  109. ColumnLayout
  110. {
  111. spacing: UM.Theme.getSize("default_margin").height
  112. anchors.fill: parent
  113. anchors.margins: UM.Theme.getSize("default_margin").width
  114. Label
  115. {
  116. text: catalog.i18nc("@title:header", "Sign in")
  117. font: UM.Theme.getFont("large_bold")
  118. color: UM.Theme.getColor("text")
  119. Layout.preferredHeight: height
  120. }
  121. Label
  122. {
  123. 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.")
  124. font: UM.Theme.getFont("medium")
  125. color: UM.Theme.getColor("text")
  126. wrapMode: Text.Wrap
  127. width: parent.width
  128. Layout.maximumWidth: width
  129. Layout.preferredHeight: height
  130. }
  131. Item
  132. {
  133. Layout.preferredWidth: parent.width
  134. Layout.fillHeight: true
  135. Image
  136. {
  137. source: UM.Theme.getImage("first_run_ultimaker_cloud")
  138. width: parent.width / 2
  139. sourceSize.width: width
  140. anchors.centerIn: parent
  141. }
  142. }
  143. Item
  144. {
  145. width: parent.width
  146. height: childrenRect.height
  147. Layout.preferredHeight: height
  148. Cura.SecondaryButton
  149. {
  150. anchors.left: parent.left
  151. text: catalog.i18nc("@button", "Sync materials with USB")
  152. onClicked: swipeView.currentIndex = removableDriveSyncPage.SwipeView.index
  153. }
  154. Cura.PrimaryButton
  155. {
  156. anchors.right: parent.right
  157. text: catalog.i18nc("@button", "Sign in")
  158. onClicked: Cura.API.account.login()
  159. }
  160. }
  161. }
  162. }
  163. Rectangle
  164. {
  165. id: printerListPage
  166. color: UM.Theme.getColor("main_background")
  167. ColumnLayout
  168. {
  169. spacing: UM.Theme.getSize("default_margin").height
  170. anchors.fill: parent
  171. anchors.margins: UM.Theme.getSize("default_margin").width
  172. visible: cloudPrinterList.count > 0
  173. Label
  174. {
  175. text: catalog.i18nc("@title:header", "The following printers will receive the new material profiles")
  176. font: UM.Theme.getFont("large_bold")
  177. color: UM.Theme.getColor("text")
  178. Layout.preferredHeight: height
  179. }
  180. ScrollView
  181. {
  182. id: printerListScrollView
  183. width: parent.width
  184. Layout.preferredWidth: width
  185. Layout.fillHeight: true
  186. clip: true
  187. ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
  188. ListView
  189. {
  190. id: printerList
  191. width: parent.width
  192. spacing: UM.Theme.getSize("default_margin").height
  193. model: cloudPrinterList
  194. delegate: Rectangle
  195. {
  196. border.color: UM.Theme.getColor("lining")
  197. border.width: UM.Theme.getSize("default_lining").width
  198. width: printerListScrollView.width
  199. height: UM.Theme.getSize("card").height
  200. Cura.IconWithText
  201. {
  202. anchors
  203. {
  204. verticalCenter: parent.verticalCenter
  205. left: parent.left
  206. leftMargin: Math.round(parent.height - height) / 2 //Equal margin on the left as above and below.
  207. right: parent.right
  208. rightMargin: Math.round(parent.height - height) / 2
  209. }
  210. text: model.name
  211. font: UM.Theme.getFont("medium")
  212. source: UM.Theme.getIcon("Printer", "medium")
  213. iconColor: UM.Theme.getColor("machine_selector_printer_icon")
  214. iconSize: UM.Theme.getSize("machine_selector_icon").width
  215. //Printer status badge (always cloud, but whether it's online or offline).
  216. UM.RecolorImage
  217. {
  218. width: UM.Theme.getSize("printer_status_icon").width
  219. height: UM.Theme.getSize("printer_status_icon").height
  220. anchors
  221. {
  222. bottom: parent.bottom
  223. bottomMargin: -Math.round(height / 6)
  224. left: parent.left
  225. leftMargin: parent.iconSize - Math.round(width * 5 / 6)
  226. }
  227. source: UM.Theme.getIcon("CloudBadge", "low")
  228. color: UM.Theme.getColor("primary")
  229. //Make a themeable circle in the background so we can change it in other themes.
  230. Rectangle
  231. {
  232. anchors.centerIn: parent
  233. 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.
  234. height: parent.height - 1.5
  235. radius: width / 2
  236. color: UM.Theme.getColor("connection_badge_background")
  237. z: parent.z - 1
  238. }
  239. }
  240. }
  241. }
  242. footer: Item
  243. {
  244. width: printerListScrollView.width
  245. height: UM.Theme.getSize("card").height + UM.Theme.getSize("default_margin").height
  246. Rectangle
  247. {
  248. border.color: UM.Theme.getColor("lining")
  249. border.width: UM.Theme.getSize("default_lining").width
  250. anchors.fill: parent
  251. anchors.topMargin: UM.Theme.getSize("default_margin").height
  252. RowLayout
  253. {
  254. anchors
  255. {
  256. fill: parent
  257. leftMargin: (parent.height - infoIcon.height) / 2 //Same margin on the left as top and bottom.
  258. rightMargin: (parent.height - infoIcon.height) / 2
  259. }
  260. spacing: UM.Theme.getSize("default_margin").width
  261. Rectangle //Info icon with a themeable color and background.
  262. {
  263. id: infoIcon
  264. width: UM.Theme.getSize("machine_selector_icon").width
  265. height: width
  266. Layout.preferredWidth: width
  267. Layout.alignment: Qt.AlignVCenter
  268. radius: height / 2
  269. color: UM.Theme.getColor("warning")
  270. UM.RecolorImage
  271. {
  272. source: UM.Theme.getIcon("EmptyInfo")
  273. anchors.fill: parent
  274. color: UM.Theme.getColor("machine_selector_printer_icon")
  275. }
  276. }
  277. Label
  278. {
  279. text: catalog.i18nc("@text Asking the user whether printers are missing in a list.", "Printers missing?")
  280. + "\n"
  281. + catalog.i18nc("@text", "Make sure all your printers are turned ON and connected to Digital Factory.")
  282. font: UM.Theme.getFont("medium")
  283. elide: Text.ElideRight
  284. Layout.alignment: Qt.AlignVCenter
  285. Layout.fillWidth: true
  286. }
  287. Cura.SecondaryButton
  288. {
  289. id: refreshListButton
  290. text: catalog.i18nc("@button", "Refresh List")
  291. iconSource: UM.Theme.getIcon("ArrowDoubleCircleRight")
  292. Layout.alignment: Qt.AlignVCenter
  293. Layout.preferredWidth: width
  294. onClicked: Cura.API.account.sync(true)
  295. }
  296. }
  297. }
  298. }
  299. }
  300. }
  301. Cura.TertiaryButton
  302. {
  303. text: catalog.i18nc("@button", "Troubleshooting")
  304. iconSource: UM.Theme.getIcon("LinkExternal")
  305. Layout.preferredHeight: height
  306. 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")
  307. }
  308. Item
  309. {
  310. width: parent.width
  311. height: childrenRect.height
  312. Layout.preferredWidth: width
  313. Layout.preferredHeight: height
  314. Cura.SecondaryButton
  315. {
  316. anchors.left: parent.left
  317. text: catalog.i18nc("@button", "Sync materials with USB")
  318. onClicked: swipeView.currentIndex = removableDriveSyncPage.SwipeView.index
  319. }
  320. Cura.PrimaryButton
  321. {
  322. anchors.right: parent.right
  323. text: catalog.i18nc("@button", "Sync")
  324. onClicked: materialManagementModel.exportUpload()
  325. enabled:
  326. {
  327. if(!materialManagementModel)
  328. {
  329. return false;
  330. }
  331. return materialManagementModel.exportUploadStatus != "uploading";
  332. }
  333. }
  334. }
  335. }
  336. ColumnLayout //Placeholder for when the user has no cloud printers.
  337. {
  338. spacing: UM.Theme.getSize("default_margin").height
  339. anchors.fill: parent
  340. anchors.margins: UM.Theme.getSize("default_margin").width
  341. visible: cloudPrinterList.count == 0
  342. Label
  343. {
  344. text: catalog.i18nc("@title:header", "No printers found")
  345. font: UM.Theme.getFont("large_bold")
  346. color: UM.Theme.getColor("text")
  347. Layout.preferredWidth: width
  348. Layout.preferredHeight: height
  349. }
  350. Image
  351. {
  352. source: UM.Theme.getImage("3d_printer_faded")
  353. sourceSize.width: width
  354. fillMode: Image.PreserveAspectFit
  355. Layout.alignment: Qt.AlignHCenter
  356. Layout.preferredWidth: parent.width / 3
  357. }
  358. Label
  359. {
  360. text: catalog.i18nc("@text", "It seems like you don't have access to any printers connected to Digital Factory.")
  361. width: parent.width
  362. horizontalAlignment: Text.AlignHCenter
  363. wrapMode: Text.Wrap
  364. Layout.preferredWidth: width
  365. Layout.preferredHeight: height
  366. }
  367. Item
  368. {
  369. Layout.preferredWidth: parent.width
  370. Layout.fillHeight: true
  371. Cura.TertiaryButton
  372. {
  373. text: catalog.i18nc("@button", "Learn how to connect your printer to Digital Factory")
  374. iconSource: UM.Theme.getIcon("LinkExternal")
  375. 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")
  376. anchors.horizontalCenter: parent.horizontalCenter
  377. }
  378. }
  379. Item
  380. {
  381. width: parent.width
  382. height: childrenRect.height
  383. Layout.preferredWidth: width
  384. Layout.preferredHeight: height
  385. Cura.SecondaryButton
  386. {
  387. anchors.left: parent.left
  388. text: catalog.i18nc("@button", "Sync materials with USB")
  389. onClicked: swipeView.currentIndex = removableDriveSyncPage.SwipeView.index
  390. }
  391. Cura.PrimaryButton
  392. {
  393. id: disabledSyncButton
  394. anchors.right: parent.right
  395. text: catalog.i18nc("@button", "Sync")
  396. enabled: false //If there are no printers, always disable this button.
  397. }
  398. Cura.SecondaryButton
  399. {
  400. anchors.right: disabledSyncButton.left
  401. anchors.rightMargin: UM.Theme.getSize("default_margin").width
  402. text: catalog.i18nc("@button", "Refresh")
  403. iconSource: UM.Theme.getIcon("ArrowDoubleCircleRight")
  404. outlineColor: "transparent"
  405. onClicked: Cura.API.account.sync(true)
  406. }
  407. }
  408. }
  409. }
  410. Rectangle
  411. {
  412. id: removableDriveSyncPage
  413. color: UM.Theme.getColor("main_background")
  414. ColumnLayout
  415. {
  416. spacing: UM.Theme.getSize("default_margin").height
  417. anchors.fill: parent
  418. anchors.margins: UM.Theme.getSize("default_margin").width
  419. Label
  420. {
  421. text: catalog.i18nc("@title:header", "Sync material profiles via USB")
  422. font: UM.Theme.getFont("large_bold")
  423. color: UM.Theme.getColor("text")
  424. Layout.preferredHeight: height
  425. }
  426. Label
  427. {
  428. 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.")
  429. font: UM.Theme.getFont("medium")
  430. color: UM.Theme.getColor("text")
  431. wrapMode: Text.Wrap
  432. width: parent.width
  433. Layout.maximumWidth: width
  434. Layout.preferredHeight: height
  435. }
  436. Row
  437. {
  438. width: parent.width
  439. Layout.preferredWidth: width
  440. Layout.fillHeight: true
  441. spacing: UM.Theme.getSize("default_margin").width
  442. Image
  443. {
  444. source: UM.Theme.getImage("insert_usb")
  445. width: parent.width / 4
  446. height: width
  447. anchors.verticalCenter: parent.verticalCenter
  448. sourceSize.width: width
  449. }
  450. Label
  451. {
  452. text: "1. " + catalog.i18nc("@text", "Click the export material archive button.")
  453. + "\n2. " + catalog.i18nc("@text", "Save the .umm file on a USB stick.")
  454. + "\n3. " + catalog.i18nc("@text", "Insert the USB stick into your printer and launch the procedure to load new material profiles.")
  455. font: UM.Theme.getFont("medium")
  456. color: UM.Theme.getColor("text")
  457. wrapMode: Text.Wrap
  458. width: parent.width * 3 / 4 - UM.Theme.getSize("default_margin").width
  459. anchors.verticalCenter: parent.verticalCenter
  460. }
  461. }
  462. Item
  463. {
  464. width: parent.width
  465. height: childrenRect.height
  466. Layout.preferredWidth: width
  467. Layout.preferredHeight: height
  468. Cura.TertiaryButton
  469. {
  470. anchors.left: parent.left
  471. text: catalog.i18nc("@button", "How to load new material profiles to my printer")
  472. iconSource: UM.Theme.getIcon("LinkExternal")
  473. 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")
  474. }
  475. Cura.PrimaryButton
  476. {
  477. anchors.right: parent.right
  478. text: catalog.i18nc("@button", "Export material archive")
  479. onClicked:
  480. {
  481. exportUsbDialog.folder = materialManagementModel.getPreferredExportAllPath();
  482. exportUsbDialog.open();
  483. }
  484. }
  485. }
  486. }
  487. }
  488. }
  489. Cura.GlobalStacksModel
  490. {
  491. id: cloudPrinterList
  492. filterConnectionType: 3 //Only show cloud connections.
  493. filterOnlineOnly: true //Only show printers that are online.
  494. }
  495. FileDialog
  496. {
  497. id: exportUsbDialog
  498. title: catalog.i18nc("@title:window", "Export All Materials")
  499. selectExisting: false
  500. nameFilters: ["Material archives (*.umm)", "All files (*)"]
  501. onAccepted:
  502. {
  503. materialManagementModel.exportAll(fileUrl);
  504. CuraApplication.setDefaultPath("dialog_material_path", folder);
  505. }
  506. }
  507. }