main.qml 11 KB

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