InstallerUi.qml 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. import QtQuick 2.0
  2. import QtQuick.Controls 2.15
  3. import QtQml.Models 2.15
  4. import "view"
  5. import "components"
  6. Item {
  7. anchors.fill: parent
  8. signal browseClicked()
  9. signal installClicked()
  10. signal updateClicked()
  11. signal preDownloadClicked()
  12. signal startClicked()
  13. signal retryClicked()
  14. signal cancelConfirmed()
  15. signal cancelRejected()
  16. signal hdiffPatchClicked()
  17. signal repatchClicked()
  18. signal stopConfirmed()
  19. signal killWineServerClicked()
  20. signal checkSelfUpdateClicked()
  21. signal checkIntegrityClicked()
  22. signal checkStopClicked()
  23. readonly property int uiStateLoading: 1
  24. readonly property int uiStateInstall: 2
  25. readonly property int uiStateInstalling: 3
  26. readonly property int uiStateUpdating: 5
  27. readonly property int uiStateStart: 6
  28. readonly property int uiStateRetry: 7
  29. readonly property int uiStateHdiffPatch: 8
  30. readonly property int uiStatePatch: 9
  31. readonly property int uiStateRunning: 10
  32. readonly property int uiStateStarting: 11
  33. readonly property int uiStateStopping: 12
  34. readonly property int uiStateWrongDir: 13
  35. readonly property int uiStateChecking: 14
  36. property bool hasUpdate: false
  37. property bool hasPreDownload: false
  38. property int uiState: uiStateLoading
  39. property alias isLogVisible: buttonLog.checked
  40. property alias progressText: textProgress.text
  41. property alias progress: progressBar.value // 0..1
  42. function log(message) {
  43. textLog.append(message)
  44. }
  45. function clearLog() {
  46. textLog.text = ""
  47. }
  48. function showLog() {
  49. buttonLog.checked = true
  50. }
  51. function confirmCancelInstall() {
  52. dialogCancelInstall.open()
  53. }
  54. Image {
  55. id: imageBackground
  56. anchors.fill: parent
  57. fillMode: Image.PreserveAspectCrop
  58. source: "qrc:/bg/bg.jpg"
  59. visible: !settings.hideBackground
  60. }
  61. Text {
  62. id: textVersion
  63. text: qsTr("Game Version:") + "\n" + (installedVersion || "?")
  64. anchors.right: parent.right
  65. anchors.top: parent.top
  66. anchors.topMargin: block * 0.75
  67. anchors.rightMargin: block
  68. horizontalAlignment: Text.AlignRight
  69. font.pixelSize: block / 1.5
  70. visible: !imageBackground.visible
  71. }
  72. Outline {
  73. id: versionOutline
  74. source: textVersion
  75. visible: imageBackground.visible
  76. }
  77. Rectangle {
  78. border.color: "black"
  79. radius: space / 4
  80. color: "#E0F0F0F0"
  81. anchors.left: parent.left
  82. anchors.right: parent.right
  83. anchors.top: parent.top
  84. anchors.bottom: buttonBar.top
  85. anchors.margins: space
  86. visible: isLogVisible
  87. Flickable {
  88. id: flickable
  89. anchors.fill: parent
  90. boundsBehavior: Flickable.DragAndOvershootBounds
  91. flickableDirection: Flickable.VerticalFlick
  92. ScrollBar.vertical: ScrollBar {
  93. id: flickScroll
  94. }
  95. TextArea.flickable: TextArea {
  96. id: textLog
  97. width: parent.width
  98. height: parent.height
  99. readOnly: true
  100. wrapMode: TextArea.Wrap
  101. persistentSelection: true
  102. bottomPadding: 0
  103. selectByMouse: true
  104. color: "black"
  105. }
  106. function append(text) {
  107. let value = textLog.text + text
  108. let endPos = flickable.contentHeight * (1.0 - flickable.visibleArea.heightRatio)
  109. let pos = flickable.contentY
  110. textLog.text = value
  111. if (pos === endPos) {
  112. flickable.contentY = endPos
  113. } else {
  114. flickable.contentY = pos
  115. }
  116. }
  117. }
  118. }
  119. Item {
  120. id: buttonBar
  121. height: block + space
  122. anchors.left: parent.left
  123. anchors.right: parent.right
  124. anchors.bottom: parent.bottom
  125. ImageButton {
  126. id: buttonSettings
  127. anchors.left: parent.left
  128. anchors.margins: space
  129. icon: "settings"
  130. enabled: uiState != uiStateInstalling && uiState != uiStateUpdating
  131. && uiState != uiStateChecking && !isPreDownloading
  132. onClicked: popupSettingsMenu.open()
  133. }
  134. ImageButton {
  135. id: buttonLog
  136. anchors.left: buttonSettings.right
  137. anchors.margins: space
  138. icon: "log"
  139. checkable: true
  140. checked: true
  141. }
  142. Text {
  143. id: textStatus
  144. visible: progressBar.visible
  145. anchors.left: textProgress.left
  146. anchors.right: textProgress.right
  147. anchors.bottom: textProgress.top
  148. anchors.bottomMargin: space / 4
  149. text: isPreDownloading ? qsTr("Pre-downloading...")
  150. : uiState == uiStateInstalling ? qsTr("Installing...")
  151. : uiState == uiStateUpdating ? qsTr("Updating...")
  152. : uiState == uiStateChecking ? qsTr("Checking...")
  153. : ""
  154. }
  155. Outline {
  156. id: textStatusOutline
  157. source: textStatus
  158. visible: textStatus.visible
  159. }
  160. Text {
  161. id: textProgress
  162. visible: progressBar.visible
  163. anchors.left: progressBar.left
  164. anchors.right: progressBar.right
  165. anchors.bottom: progressBar.top
  166. anchors.bottomMargin: space / 2
  167. elide: Text.ElideRight
  168. }
  169. Outline {
  170. id: textProgressOutline
  171. source: textProgress
  172. visible: textProgress.visible
  173. }
  174. ProgressBar {
  175. id: progressBar
  176. visible: isPreDownloading || uiState == uiStateInstalling
  177. || uiState == uiStateUpdating || uiState == uiStateChecking
  178. anchors.left: buttonLog.right
  179. anchors.right: buttonUpdate.visible ? buttonUpdate.left
  180. : buttonBrowse.visible ? buttonBrowse.left
  181. : buttonInstallUpdate.left
  182. anchors.bottom: parent.bottom
  183. anchors.margins: space
  184. }
  185. Button {
  186. id: buttonBrowse
  187. visible: uiState == uiStateInstall || uiState == uiStateWrongDir
  188. title: qsTr("Browse...")
  189. anchors.right: buttonInstallUpdate.left
  190. anchors.margins: space
  191. onClicked: browseClicked()
  192. }
  193. Button {
  194. id: buttonUpdate
  195. visible: hasUpdate && (uiState == uiStateStart || uiState == uiStatePatch) || hasPreDownload
  196. title: !hasPreDownload ? (qsTr("Update to") + " v" + availableVersion)
  197. : isPreDownloading ? qsTr("Stop\nPre-Download")
  198. : (qsTr("Pre-Download") + "\nv" + preDownloadVersion)
  199. anchors.right: buttonInstallUpdate.left
  200. anchors.margins: space
  201. onClicked: isPreDownloading ? cancelConfirmed()
  202. : hasPreDownload ? preDownloadClicked() : updateClicked()
  203. }
  204. Button {
  205. id: buttonInstallUpdate
  206. title: uiState == uiStateInstall ? qsTr("Install")
  207. : uiState == uiStateRetry ? qsTr("Retry")
  208. : uiState == uiStateLoading ? qsTr("Loading...")
  209. : uiState == uiStateInstalling ? qsTr("Cancel")
  210. : uiState == uiStateUpdating ? qsTr("Cancel")
  211. : uiState == uiStateStart ? (qsTr("Start") + (hasUpdate ? (" v" + localVersionLoader.version) : ""))
  212. : uiState == uiStateHdiffPatch ? qsTr("Update")
  213. : uiState == uiStatePatch ? qsTr("Patch")
  214. : uiState == uiStateRunning ? qsTr("Stop")
  215. : uiState == uiStateStarting ? qsTr("Starting...")
  216. : uiState == uiStateStopping ? qsTr("Stopping...")
  217. : uiState == uiStateWrongDir ? qsTr("Install")
  218. : uiState == uiStateChecking ? qsTr("Cancel")
  219. : ""
  220. anchors.right: parent.right
  221. anchors.margins: space
  222. enabled: uiState != uiStateLoading
  223. && uiState != uiStateStarting
  224. && uiState != uiStateStopping
  225. && uiState != uiStateWrongDir
  226. && (!isPreDownloading || (uiState != uiStateInstall && uiState != uiStatePatch))
  227. onClicked: uiState == uiStateInstall ? installClicked()
  228. : uiState == uiStateInstalling ? confirmCancelInstall()
  229. : uiState == uiStateUpdating ? confirmCancelInstall()
  230. : uiState == uiStateStart ? startClicked()
  231. : uiState == uiStateRetry ? retryClicked()
  232. : uiState == uiStateHdiffPatch ? hdiffPatchClicked()
  233. : uiState == uiStatePatch ? repatchClicked()
  234. : uiState == uiStateRunning ? dialogStopClient.open()
  235. : uiState == uiStateChecking ? checkStopClicked()
  236. : undefined
  237. }
  238. }
  239. Dialog {
  240. id: dialogCancelInstall
  241. anchors.centerIn: parent
  242. title: window.title
  243. standardButtons: Dialog.Yes | Dialog.No
  244. modal: true
  245. focus: true
  246. Text {
  247. id: textDialog
  248. anchors.fill: parent
  249. text: qsTr("Some tasks are still running. Do you wish to stop them?")
  250. }
  251. onAccepted: cancelConfirmed()
  252. onRejected: cancelRejected()
  253. }
  254. Dialog {
  255. id: dialogStopClient
  256. anchors.centerIn: parent
  257. title: window.title
  258. standardButtons: Dialog.Yes | Dialog.No
  259. modal: true
  260. focus: true
  261. Text {
  262. anchors.fill: parent
  263. text: qsTr("Please use this only as emergency option.")
  264. + "\n" + qsTr("Do you wish to terminate client?")
  265. }
  266. onAccepted: stopConfirmed()
  267. }
  268. Dialog {
  269. id: dialogFirstRun
  270. anchors.centerIn: parent
  271. title: window.title
  272. standardButtons: Dialog.Ok
  273. modal: true
  274. focus: true
  275. Text {
  276. anchors.fill: parent
  277. text: qsTr("The game is not meant to run on Linux. It may also break at any time.\nThere's absolutely no guarantee.")
  278. }
  279. Component.onCompleted: {
  280. if (settings.firstRun) {
  281. settings.firstRun = false
  282. dialogFirstRun.open()
  283. }
  284. }
  285. }
  286. Dialog {
  287. id: dialogAbout
  288. anchors.centerIn: parent
  289. title: window.title
  290. standardButtons: Dialog.Ok
  291. modal: true
  292. focus: true
  293. Row {
  294. anchors.fill: parent
  295. spacing: space
  296. Image {
  297. id: aboutIcon
  298. source: "qrc:/appicon/paimon-launcher.png"
  299. }
  300. Text {
  301. textFormat: Text.RichText
  302. onLinkActivated: Qt.openUrlExternally(link)
  303. text: "Original workaround project: <a href='" + patchRepo + "'>Dawn</a><br/>"
  304. + "<a href='" + patchRepo + "/src/master/TROUBLESHOOTING.md'>Troubleshooting page</a><br/>"
  305. + "<a href='" + patchRepo + "/src/master/TWEAKS.md'>Game Tweaks</a><br/>"
  306. + "<br/><br/>"
  307. + "<a href='https://notabug.org/loentar/paimon-launcher/releases'>Check for new versions of launcher here</a><br/><br/>"
  308. + "For bug reports please visit <br/>"
  309. + "<a href='https://notabug.org/loentar/paimon-launcher/issues'>Paimon Launcher Issues</a><br/><br/>"
  310. + "Copyright © Loentar 2022"
  311. }
  312. }
  313. }
  314. Script {
  315. id: script
  316. function openWineConfig() {
  317. execScript('client-wrapper', 'wineconfig')
  318. }
  319. }
  320. Popup {
  321. id: popupSettingsMenu
  322. x: buttonSettings.x
  323. y: parent.height - buttonSettings.height - height - space
  324. width: block * 7
  325. height: block * 0.8 * listMenu.model.count
  326. padding: 0
  327. focus: true
  328. clip: true
  329. closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
  330. background: Rectangle {
  331. color: "lightgray"
  332. border.color: "black"
  333. radius: space / 4
  334. }
  335. ListView {
  336. id: listMenu
  337. interactive: false
  338. anchors.fill: parent
  339. model: ListModel {
  340. ListElement { name: "browse"; text: qsTr("Change Game location...") }
  341. ListElement { name: "hidebg"; text: qsTr("Hide background") }
  342. ListElement { name: "clearlog"; text: qsTr("Clear log") }
  343. ListElement { name: "speedup"; text: qsTr("Speedup downloads") }
  344. ListElement { name: "limitdl"; text: qsTr("Limit download speed") }
  345. ListElement { name: "repatch"; text: qsTr("Re-apply Wine patch") }
  346. ListElement { name: "killwine"; text: qsTr("Kill wineserver") }
  347. ListElement { name: "editwine"; text: qsTr("Edit wineconfig.sh") }
  348. ListElement { name: "integrity"; text: qsTr("Run integrity check...") }
  349. ListElement { name: "checkupdate"; text: qsTr("Check for Launcher updates at startup") }
  350. ListElement { name: "selfupdate"; text: qsTr("Check for Launcher updates now...") }
  351. ListElement { name: "about"; text: qsTr("About...") }
  352. }
  353. delegate: Button {
  354. checkBox: model.name === "speedup"
  355. || model.name === "limitdl"
  356. || model.name === "hidebg"
  357. || model.name === "checkupdate"
  358. checked: (model.name === "speedup" && settings.multiConnections) ||
  359. (model.name === "limitdl" && settings.limitDownload) ||
  360. (model.name === "checkupdate" && settings.checkLauncherUpdatesAtStartup) ||
  361. (model.name === "hidebg" && settings.hideBackground)
  362. title: model.text
  363. enabled: (model.name !== "repatch" && model.name !== "integrity") || !!installedVersion
  364. width: listMenu.width
  365. height: block * 0.8
  366. menu: true
  367. horizontalAlignment: Text.AlignLeft
  368. onClicked: {
  369. popupSettingsMenu.close()
  370. switch (model.name) {
  371. case "browse":
  372. browseClicked()
  373. break
  374. case "hidebg":
  375. settings.hideBackground = !settings.hideBackground
  376. break
  377. case "clearlog":
  378. clearLog()
  379. break
  380. case "limitdl":
  381. settings.limitDownload = !settings.limitDownload
  382. break
  383. case "speedup":
  384. settings.multiConnections = !settings.multiConnections
  385. break
  386. case "repatch":
  387. repatchClicked()
  388. break
  389. case "killwine":
  390. killWineServerClicked()
  391. break
  392. case "editwine":
  393. script.openWineConfig()
  394. break
  395. case "integrity":
  396. checkIntegrityClicked()
  397. break
  398. case "checkupdate":
  399. settings.checkLauncherUpdatesAtStartup = !settings.checkLauncherUpdatesAtStartup
  400. break
  401. case "selfupdate":
  402. checkSelfUpdateClicked()
  403. break
  404. case "about":
  405. dialogAbout.open()
  406. break
  407. }
  408. }
  409. }
  410. }
  411. }
  412. }