1
0

main.qml 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. import QtQuick 2.15
  2. import QtQuick.Controls 2.15
  3. import QtQuick.Layouts 1.15
  4. import QtQuick.Dialogs
  5. import QtQuick.VirtualKeyboard 2.15
  6. import DuneWeaver 1.0
  7. import "components"
  8. import "components" as Components
  9. ApplicationWindow {
  10. id: window
  11. visible: true
  12. width: 800
  13. height: 480
  14. title: "Dune Weaver Touch"
  15. // Solid background color for ApplicationWindow
  16. color: Components.ThemeManager.backgroundColor
  17. property int currentPageIndex: 0
  18. property alias stackView: stackView
  19. property alias backend: backend
  20. property bool shouldNavigateToExecution: false
  21. property string currentPatternName: ""
  22. property string currentPatternPreview: ""
  23. onCurrentPageIndexChanged: {
  24. }
  25. onShouldNavigateToExecutionChanged: {
  26. if (shouldNavigateToExecution) {
  27. // If we're in a sub-page (like PatternDetailPage), pop back to main view first
  28. if (stackView.depth > 1) {
  29. stackView.pop()
  30. }
  31. // Then navigate to ExecutionPage tab (index 4)
  32. currentPageIndex = 4
  33. shouldNavigateToExecution = false
  34. }
  35. }
  36. Backend {
  37. id: backend
  38. onExecutionStarted: function(patternName, patternPreview) {
  39. // Store pattern info for ExecutionPage
  40. window.currentPatternName = patternName
  41. window.currentPatternPreview = patternPreview
  42. // Navigate to Execution tab (index 3) instead of pushing page
  43. shouldNavigateToExecution = true
  44. }
  45. onErrorOccurred: function(error) {
  46. // Use custom dialog on Pi 5 for proper rotation
  47. if (typeof rotateDisplay !== 'undefined' && rotateDisplay) {
  48. customErrorDialog.errorText = error
  49. customErrorDialog.open()
  50. } else {
  51. errorDialog.text = error
  52. errorDialog.open()
  53. }
  54. }
  55. onScreenStateChanged: function(isOn) {
  56. }
  57. onBackendConnectionChanged: function(connected) {
  58. if (connected && stackView.currentItem.toString().indexOf("ConnectionSplash") !== -1) {
  59. stackView.replace(mainSwipeView)
  60. } else if (!connected && stackView.currentItem.toString().indexOf("ConnectionSplash") === -1) {
  61. stackView.replace(connectionSplash)
  62. }
  63. }
  64. }
  65. // Global touch/mouse handler for activity tracking
  66. MouseArea {
  67. anchors.fill: parent
  68. acceptedButtons: Qt.NoButton // Don't interfere with other mouse areas
  69. hoverEnabled: true
  70. propagateComposedEvents: true
  71. onPressed: {
  72. backend.resetActivityTimer()
  73. }
  74. onPositionChanged: {
  75. backend.resetActivityTimer()
  76. }
  77. onClicked: {
  78. backend.resetActivityTimer()
  79. }
  80. }
  81. PatternModel {
  82. id: patternModel
  83. }
  84. // Rotation container for Pi 5
  85. Item {
  86. id: rotationContainer
  87. anchors.fill: parent
  88. rotation: typeof rotateDisplay !== 'undefined' && rotateDisplay ? 180 : 0
  89. transformOrigin: Item.Center
  90. StackView {
  91. id: stackView
  92. anchors.fill: parent
  93. initialItem: backend.backendConnected ? mainSwipeView : connectionSplash
  94. Component {
  95. id: connectionSplash
  96. ConnectionSplash {
  97. statusText: backend.reconnectStatus
  98. showRetryButton: backend.reconnectStatus === "Cannot connect to backend"
  99. onRetryConnection: {
  100. backend.retryConnection()
  101. }
  102. }
  103. }
  104. Component {
  105. id: mainSwipeView
  106. Item {
  107. // Main content area
  108. StackLayout {
  109. id: stackLayout
  110. anchors.top: parent.top
  111. anchors.left: parent.left
  112. anchors.right: parent.right
  113. anchors.bottom: bottomNav.top
  114. currentIndex: window.currentPageIndex
  115. Component.onCompleted: {
  116. }
  117. // Patterns Page
  118. Loader {
  119. source: "pages/ModernPatternListPage.qml"
  120. onLoaded: {
  121. item.patternModel = patternModel
  122. item.backend = backend
  123. item.stackView = stackView
  124. }
  125. }
  126. // Playlists Page
  127. Loader {
  128. source: "pages/ModernPlaylistPage.qml"
  129. onLoaded: {
  130. item.backend = backend
  131. item.stackView = stackView
  132. item.mainWindow = window
  133. }
  134. }
  135. // Control Page
  136. Loader {
  137. source: "pages/TableControlPage.qml"
  138. onLoaded: {
  139. item.backend = backend
  140. }
  141. }
  142. // LED Control Page (index 3)
  143. Loader {
  144. source: "pages/LedControlPage.qml"
  145. onLoaded: {
  146. item.backend = backend
  147. }
  148. }
  149. // Execution Page (index 4)
  150. Loader {
  151. source: "pages/ExecutionPage.qml"
  152. onLoaded: {
  153. item.backend = backend
  154. item.stackView = stackView
  155. item.patternName = Qt.binding(function() { return window.currentPatternName })
  156. item.patternPreview = Qt.binding(function() { return window.currentPatternPreview })
  157. }
  158. }
  159. }
  160. // Bottom Navigation
  161. BottomNavigation {
  162. id: bottomNav
  163. anchors.bottom: parent.bottom
  164. anchors.left: parent.left
  165. anchors.right: parent.right
  166. currentIndex: window.currentPageIndex
  167. onTabClicked: function(index) {
  168. window.currentPageIndex = index
  169. }
  170. }
  171. }
  172. }
  173. }
  174. } // End rotationContainer
  175. // Virtual Keyboard Support - outside rotation container for proper positioning
  176. InputPanel {
  177. id: inputPanel
  178. z: 99999
  179. y: window.height
  180. anchors.left: parent.left
  181. anchors.right: parent.right
  182. // Rotate keyboard for Pi 5
  183. rotation: typeof rotateDisplay !== 'undefined' && rotateDisplay ? 180 : 0
  184. transformOrigin: Item.Center
  185. states: State {
  186. name: "visible"
  187. when: inputPanel.active
  188. PropertyChanges {
  189. target: inputPanel
  190. y: typeof rotateDisplay !== 'undefined' && rotateDisplay ? 0 : window.height - inputPanel.height
  191. }
  192. }
  193. transitions: Transition {
  194. from: ""
  195. to: "visible"
  196. reversible: true
  197. ParallelAnimation {
  198. NumberAnimation {
  199. target: inputPanel
  200. property: "y"
  201. duration: 250
  202. easing.type: Easing.InOutQuad
  203. }
  204. }
  205. }
  206. }
  207. // Error dialog - note: MessageDialog is a system dialog, rotation may not work
  208. // If rotation doesn't work, we'll need to replace with a custom Dialog
  209. MessageDialog {
  210. id: errorDialog
  211. title: "Error"
  212. buttons: MessageDialog.Ok
  213. }
  214. // Custom error dialog as fallback for Pi 5 rotation
  215. Popup {
  216. id: customErrorDialog
  217. modal: true
  218. x: (window.width - width) / 2
  219. y: (window.height - height) / 2
  220. width: 320
  221. height: 180
  222. closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
  223. property string errorText: ""
  224. background: Rectangle {
  225. color: "#2d2d2d"
  226. radius: 12
  227. border.color: "#404040"
  228. border.width: 1
  229. // Rotate the entire dialog content for Pi 5
  230. rotation: typeof rotateDisplay !== 'undefined' && rotateDisplay ? 180 : 0
  231. transformOrigin: Item.Center
  232. }
  233. contentItem: Item {
  234. rotation: typeof rotateDisplay !== 'undefined' && rotateDisplay ? 180 : 0
  235. transformOrigin: Item.Center
  236. Column {
  237. anchors.fill: parent
  238. anchors.margins: 20
  239. spacing: 15
  240. Label {
  241. text: "Error"
  242. font.pixelSize: 18
  243. font.bold: true
  244. color: "#ff6b6b"
  245. anchors.horizontalCenter: parent.horizontalCenter
  246. }
  247. Label {
  248. text: customErrorDialog.errorText
  249. wrapMode: Text.WordWrap
  250. width: parent.width
  251. horizontalAlignment: Text.AlignHCenter
  252. color: "#ffffff"
  253. font.pixelSize: 14
  254. }
  255. Button {
  256. text: "OK"
  257. anchors.horizontalCenter: parent.horizontalCenter
  258. onClicked: customErrorDialog.close()
  259. }
  260. }
  261. }
  262. }
  263. }