1
0

main.qml 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  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. onPatternsUpdated: function(patternFile) {
  77. console.log("📥 QML: Patterns updated notification received:", patternFile)
  78. console.log("📥 Refreshing pattern model to pick up new pattern/preview")
  79. patternModel.refresh()
  80. }
  81. }
  82. // Global touch/mouse handler for activity tracking
  83. MouseArea {
  84. anchors.fill: parent
  85. acceptedButtons: Qt.NoButton // Don't interfere with other mouse areas
  86. hoverEnabled: true
  87. propagateComposedEvents: true
  88. onPressed: {
  89. console.log("🖥️ QML: Touch/press detected - resetting activity timer")
  90. backend.resetActivityTimer()
  91. }
  92. onPositionChanged: {
  93. console.log("🖥️ QML: Mouse movement detected - resetting activity timer")
  94. backend.resetActivityTimer()
  95. }
  96. onClicked: {
  97. console.log("🖥️ QML: Click detected - resetting activity timer")
  98. backend.resetActivityTimer()
  99. }
  100. }
  101. PatternModel {
  102. id: patternModel
  103. }
  104. // Rotation container for Pi 5
  105. Item {
  106. id: rotationContainer
  107. anchors.fill: parent
  108. rotation: typeof rotateDisplay !== 'undefined' && rotateDisplay ? 180 : 0
  109. transformOrigin: Item.Center
  110. StackView {
  111. id: stackView
  112. anchors.fill: parent
  113. initialItem: backend.backendConnected ? mainSwipeView : connectionSplash
  114. Component {
  115. id: connectionSplash
  116. ConnectionSplash {
  117. statusText: backend.reconnectStatus
  118. showRetryButton: backend.reconnectStatus === "Cannot connect to backend"
  119. onRetryConnection: {
  120. console.log("🔄 Manual retry requested")
  121. backend.retryConnection()
  122. }
  123. }
  124. }
  125. Component {
  126. id: mainSwipeView
  127. Item {
  128. // Main content area
  129. StackLayout {
  130. id: stackLayout
  131. anchors.top: parent.top
  132. anchors.left: parent.left
  133. anchors.right: parent.right
  134. anchors.bottom: bottomNav.top
  135. currentIndex: window.currentPageIndex
  136. Component.onCompleted: {
  137. console.log("📱 StackLayout created with currentIndex:", currentIndex, "bound to window.currentPageIndex:", window.currentPageIndex)
  138. }
  139. // Patterns Page
  140. Loader {
  141. source: "pages/ModernPatternListPage.qml"
  142. onLoaded: {
  143. item.patternModel = patternModel
  144. item.backend = backend
  145. item.stackView = stackView
  146. }
  147. }
  148. // Playlists Page
  149. Loader {
  150. source: "pages/ModernPlaylistPage.qml"
  151. onLoaded: {
  152. item.backend = backend
  153. item.stackView = stackView
  154. item.mainWindow = window
  155. }
  156. }
  157. // Control Page
  158. Loader {
  159. source: "pages/TableControlPage.qml"
  160. onLoaded: {
  161. item.backend = backend
  162. }
  163. }
  164. // LED Control Page (index 3)
  165. Loader {
  166. source: "pages/LedControlPage.qml"
  167. onLoaded: {
  168. item.backend = backend
  169. }
  170. }
  171. // Execution Page (index 4)
  172. Loader {
  173. source: "pages/ExecutionPage.qml"
  174. onLoaded: {
  175. item.backend = backend
  176. item.stackView = stackView
  177. item.patternName = Qt.binding(function() { return window.currentPatternName })
  178. item.patternPreview = Qt.binding(function() { return window.currentPatternPreview })
  179. }
  180. }
  181. }
  182. // Bottom Navigation
  183. BottomNavigation {
  184. id: bottomNav
  185. anchors.bottom: parent.bottom
  186. anchors.left: parent.left
  187. anchors.right: parent.right
  188. currentIndex: window.currentPageIndex
  189. onTabClicked: function(index) {
  190. console.log("📱 Tab clicked:", index)
  191. window.currentPageIndex = index
  192. }
  193. }
  194. }
  195. }
  196. }
  197. } // End rotationContainer
  198. // Virtual Keyboard Support - outside rotation container for proper positioning
  199. InputPanel {
  200. id: inputPanel
  201. z: 99999
  202. y: window.height
  203. anchors.left: parent.left
  204. anchors.right: parent.right
  205. // Rotate keyboard for Pi 5
  206. rotation: typeof rotateDisplay !== 'undefined' && rotateDisplay ? 180 : 0
  207. transformOrigin: Item.Center
  208. states: State {
  209. name: "visible"
  210. when: inputPanel.active
  211. PropertyChanges {
  212. target: inputPanel
  213. y: typeof rotateDisplay !== 'undefined' && rotateDisplay ? 0 : window.height - inputPanel.height
  214. }
  215. }
  216. transitions: Transition {
  217. from: ""
  218. to: "visible"
  219. reversible: true
  220. ParallelAnimation {
  221. NumberAnimation {
  222. target: inputPanel
  223. property: "y"
  224. duration: 250
  225. easing.type: Easing.InOutQuad
  226. }
  227. }
  228. }
  229. }
  230. // Error dialog - note: MessageDialog is a system dialog, rotation may not work
  231. // If rotation doesn't work, we'll need to replace with a custom Dialog
  232. MessageDialog {
  233. id: errorDialog
  234. title: "Error"
  235. buttons: MessageDialog.Ok
  236. }
  237. // Custom error dialog as fallback for Pi 5 rotation
  238. Popup {
  239. id: customErrorDialog
  240. modal: true
  241. x: (window.width - width) / 2
  242. y: (window.height - height) / 2
  243. width: 320
  244. height: 180
  245. closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
  246. property string errorText: ""
  247. background: Rectangle {
  248. color: "#2d2d2d"
  249. radius: 12
  250. border.color: "#404040"
  251. border.width: 1
  252. // Rotate the entire dialog content for Pi 5
  253. rotation: typeof rotateDisplay !== 'undefined' && rotateDisplay ? 180 : 0
  254. transformOrigin: Item.Center
  255. }
  256. contentItem: Item {
  257. rotation: typeof rotateDisplay !== 'undefined' && rotateDisplay ? 180 : 0
  258. transformOrigin: Item.Center
  259. Column {
  260. anchors.fill: parent
  261. anchors.margins: 20
  262. spacing: 15
  263. Label {
  264. text: "Error"
  265. font.pixelSize: 18
  266. font.bold: true
  267. color: "#ff6b6b"
  268. anchors.horizontalCenter: parent.horizontalCenter
  269. }
  270. Label {
  271. text: customErrorDialog.errorText
  272. wrapMode: Text.WordWrap
  273. width: parent.width
  274. horizontalAlignment: Text.AlignHCenter
  275. color: "#ffffff"
  276. font.pixelSize: 14
  277. }
  278. Button {
  279. text: "OK"
  280. anchors.horizontalCenter: parent.horizontalCenter
  281. onClicked: customErrorDialog.close()
  282. }
  283. }
  284. }
  285. }
  286. }