ModernPlaylistPage.qml 59 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089
  1. import QtQuick 2.15
  2. import QtQuick.Controls 2.15
  3. import QtQuick.Layouts 1.15
  4. import DuneWeaver 1.0
  5. import "../components"
  6. import "../components" as Components
  7. Page {
  8. id: page
  9. property var backend: null
  10. property var stackView: null
  11. property var mainWindow: null
  12. // State management for navigation
  13. property bool showingPlaylistDetail: false
  14. property string selectedPlaylist: ""
  15. property var selectedPlaylistData: null
  16. property var currentPlaylistPatterns: []
  17. // Playlist execution settings
  18. property real pauseTime: backend ? backend.pauseBetweenPatterns : 0
  19. property string clearPattern: "adaptive"
  20. property string runMode: "single"
  21. property bool shuffle: false
  22. PlaylistModel {
  23. id: playlistModel
  24. }
  25. // Update patterns when playlist selection changes
  26. onSelectedPlaylistChanged: {
  27. if (selectedPlaylist) {
  28. currentPlaylistPatterns = playlistModel.getPatternsForPlaylist(selectedPlaylist)
  29. console.log("Loaded patterns for", selectedPlaylist + ":", currentPlaylistPatterns)
  30. } else {
  31. currentPlaylistPatterns = []
  32. }
  33. }
  34. // Debug playlist loading
  35. Component.onCompleted: {
  36. console.log("ModernPlaylistPage completed, playlist count:", playlistModel.rowCount())
  37. console.log("showingPlaylistDetail:", showingPlaylistDetail)
  38. }
  39. // Function to navigate to playlist detail
  40. function showPlaylistDetail(playlistName, playlistData) {
  41. selectedPlaylist = playlistName
  42. selectedPlaylistData = playlistData
  43. showingPlaylistDetail = true
  44. }
  45. // Function to go back to playlist list
  46. function showPlaylistList() {
  47. showingPlaylistDetail = false
  48. selectedPlaylist = ""
  49. selectedPlaylistData = null
  50. }
  51. Rectangle {
  52. anchors.fill: parent
  53. color: Components.ThemeManager.backgroundColor
  54. }
  55. // Playlist List View (shown by default)
  56. Rectangle {
  57. id: playlistListView
  58. anchors.fill: parent
  59. color: Components.ThemeManager.backgroundColor
  60. visible: !showingPlaylistDetail
  61. ColumnLayout {
  62. anchors.fill: parent
  63. spacing: 0
  64. // Header
  65. Rectangle {
  66. Layout.fillWidth: true
  67. Layout.preferredHeight: 50
  68. color: Components.ThemeManager.surfaceColor
  69. // Bottom border
  70. Rectangle {
  71. anchors.bottom: parent.bottom
  72. width: parent.width
  73. height: 1
  74. color: Components.ThemeManager.borderColor
  75. }
  76. RowLayout {
  77. anchors.fill: parent
  78. anchors.leftMargin: 15
  79. anchors.rightMargin: 10
  80. ConnectionStatus {
  81. backend: page.backend
  82. Layout.rightMargin: 8
  83. }
  84. Label {
  85. text: "Playlists"
  86. font.pixelSize: 18
  87. font.bold: true
  88. color: Components.ThemeManager.textPrimary
  89. }
  90. Label {
  91. text: playlistModel.rowCount() + " playlists"
  92. font.pixelSize: 12
  93. color: Components.ThemeManager.textTertiary
  94. }
  95. Item {
  96. Layout.fillWidth: true
  97. }
  98. }
  99. }
  100. // Playlist List
  101. ListView {
  102. Layout.fillWidth: true
  103. Layout.fillHeight: true
  104. Layout.margins: 15
  105. model: playlistModel
  106. spacing: 12
  107. clip: true
  108. ScrollBar.vertical: ScrollBar {
  109. active: true
  110. policy: ScrollBar.AsNeeded
  111. }
  112. delegate: Rectangle {
  113. width: ListView.view.width
  114. height: 80
  115. color: Components.ThemeManager.surfaceColor
  116. radius: 12
  117. border.color: Components.ThemeManager.borderColor
  118. border.width: 1
  119. // Press animation
  120. scale: mouseArea.pressed ? 0.98 : 1.0
  121. Behavior on scale {
  122. NumberAnimation { duration: 100; easing.type: Easing.OutQuad }
  123. }
  124. RowLayout {
  125. anchors.fill: parent
  126. anchors.margins: 20
  127. spacing: 15
  128. // Icon
  129. Rectangle {
  130. Layout.preferredWidth: 40
  131. Layout.preferredHeight: 40
  132. radius: 20
  133. color: Components.ThemeManager.darkMode ? "#1e3a5f" : "#e3f2fd"
  134. Text {
  135. anchors.centerIn: parent
  136. text: "♪"
  137. font.pixelSize: 18
  138. color: "#2196F3"
  139. }
  140. }
  141. // Playlist info
  142. Column {
  143. Layout.fillWidth: true
  144. spacing: 4
  145. Label {
  146. text: model.name
  147. font.pixelSize: 16
  148. font.bold: true
  149. color: Components.ThemeManager.textPrimary
  150. elide: Text.ElideRight
  151. width: parent.width
  152. }
  153. Label {
  154. text: model.itemCount + " patterns"
  155. color: Components.ThemeManager.textSecondary
  156. font.pixelSize: 12
  157. }
  158. }
  159. // Arrow
  160. Text {
  161. text: "▶"
  162. font.pixelSize: 16
  163. color: Components.ThemeManager.textTertiary
  164. }
  165. }
  166. MouseArea {
  167. id: mouseArea
  168. anchors.fill: parent
  169. onClicked: {
  170. showPlaylistDetail(model.name, model)
  171. }
  172. }
  173. }
  174. // Empty state
  175. Rectangle {
  176. anchors.fill: parent
  177. color: "transparent"
  178. visible: playlistModel.rowCount() === 0
  179. Column {
  180. anchors.centerIn: parent
  181. spacing: 15
  182. Text {
  183. text: "♪"
  184. color: Components.ThemeManager.placeholderText
  185. font.pixelSize: 64
  186. anchors.horizontalCenter: parent.horizontalCenter
  187. }
  188. Label {
  189. text: "No playlists found"
  190. anchors.horizontalCenter: parent.horizontalCenter
  191. color: Components.ThemeManager.textSecondary
  192. font.pixelSize: 18
  193. }
  194. Label {
  195. text: "Create playlists to organize\\nyour pattern collections"
  196. anchors.horizontalCenter: parent.horizontalCenter
  197. color: Components.ThemeManager.textTertiary
  198. font.pixelSize: 14
  199. horizontalAlignment: Text.AlignHCenter
  200. }
  201. }
  202. }
  203. }
  204. }
  205. }
  206. // Playlist Detail View (shown when a playlist is selected)
  207. Rectangle {
  208. id: playlistDetailView
  209. anchors.fill: parent
  210. color: Components.ThemeManager.backgroundColor
  211. visible: showingPlaylistDetail
  212. ColumnLayout {
  213. anchors.fill: parent
  214. spacing: 0
  215. // Header with back button
  216. Rectangle {
  217. Layout.fillWidth: true
  218. Layout.preferredHeight: 50
  219. color: Components.ThemeManager.surfaceColor
  220. // Bottom border
  221. Rectangle {
  222. anchors.bottom: parent.bottom
  223. width: parent.width
  224. height: 1
  225. color: Components.ThemeManager.borderColor
  226. }
  227. RowLayout {
  228. anchors.fill: parent
  229. anchors.leftMargin: 15
  230. anchors.rightMargin: 10
  231. spacing: 10
  232. ConnectionStatus {
  233. backend: page.backend
  234. Layout.rightMargin: 8
  235. }
  236. Button {
  237. text: "← Back"
  238. font.pixelSize: 14
  239. flat: true
  240. onClicked: showPlaylistList()
  241. contentItem: Text {
  242. text: parent.text
  243. font: parent.font
  244. color: Components.ThemeManager.textPrimary
  245. horizontalAlignment: Text.AlignHCenter
  246. verticalAlignment: Text.AlignVCenter
  247. }
  248. }
  249. Label {
  250. text: selectedPlaylist
  251. font.pixelSize: 18
  252. font.bold: true
  253. color: Components.ThemeManager.textPrimary
  254. Layout.fillWidth: true
  255. elide: Text.ElideRight
  256. }
  257. Label {
  258. text: currentPlaylistPatterns.length + " patterns"
  259. font.pixelSize: 12
  260. color: Components.ThemeManager.textTertiary
  261. }
  262. }
  263. }
  264. // Content - Pattern list on left, controls on right
  265. Item {
  266. Layout.fillWidth: true
  267. Layout.fillHeight: true
  268. Row {
  269. anchors.fill: parent
  270. spacing: 0
  271. // Left side - Pattern List (40% of width)
  272. Rectangle {
  273. width: parent.width * 0.4
  274. height: parent.height
  275. color: Components.ThemeManager.surfaceColor
  276. ColumnLayout {
  277. anchors.fill: parent
  278. anchors.margins: 15
  279. spacing: 10
  280. Label {
  281. text: "Patterns"
  282. font.pixelSize: 14
  283. font.bold: true
  284. color: Components.ThemeManager.textPrimary
  285. }
  286. ScrollView {
  287. Layout.fillWidth: true
  288. Layout.fillHeight: true
  289. clip: true
  290. ListView {
  291. id: patternListView
  292. width: parent.width
  293. model: currentPlaylistPatterns
  294. spacing: 6
  295. delegate: Rectangle {
  296. width: patternListView.width
  297. height: 35
  298. color: index % 2 === 0 ? Components.ThemeManager.cardColor : Components.ThemeManager.surfaceColor
  299. radius: 6
  300. border.color: Components.ThemeManager.borderColor
  301. border.width: 1
  302. RowLayout {
  303. anchors.fill: parent
  304. anchors.margins: 10
  305. spacing: 8
  306. Label {
  307. text: (index + 1) + "."
  308. font.pixelSize: 11
  309. color: Components.ThemeManager.textSecondary
  310. Layout.preferredWidth: 25
  311. }
  312. Label {
  313. text: modelData
  314. font.pixelSize: 11
  315. color: Components.ThemeManager.textPrimary
  316. Layout.fillWidth: true
  317. elide: Text.ElideRight
  318. }
  319. }
  320. }
  321. }
  322. }
  323. // Empty playlist message
  324. Rectangle {
  325. Layout.fillWidth: true
  326. Layout.fillHeight: true
  327. color: "transparent"
  328. visible: currentPlaylistPatterns.length === 0
  329. Column {
  330. anchors.centerIn: parent
  331. spacing: 10
  332. Text {
  333. text: "♪"
  334. font.pixelSize: 32
  335. color: Components.ThemeManager.placeholderText
  336. anchors.horizontalCenter: parent.horizontalCenter
  337. }
  338. Label {
  339. text: "Empty playlist"
  340. anchors.horizontalCenter: parent.horizontalCenter
  341. color: Components.ThemeManager.textSecondary
  342. font.pixelSize: 14
  343. }
  344. }
  345. }
  346. }
  347. }
  348. // Divider
  349. Rectangle {
  350. width: 1
  351. height: parent.height
  352. color: Components.ThemeManager.borderColor
  353. }
  354. // Right side - Full height controls (60% of width)
  355. Rectangle {
  356. width: parent.width * 0.6 - 1
  357. height: parent.height
  358. color: Components.ThemeManager.surfaceColor
  359. ColumnLayout {
  360. anchors.fill: parent
  361. anchors.margins: 15
  362. spacing: 15
  363. Label {
  364. text: "Playlist Controls"
  365. font.pixelSize: 16
  366. font.bold: true
  367. color: Components.ThemeManager.textPrimary
  368. }
  369. // Main execution buttons
  370. RowLayout {
  371. Layout.fillWidth: true
  372. spacing: 10
  373. // Play Playlist button
  374. Rectangle {
  375. Layout.fillWidth: true
  376. Layout.preferredHeight: 45
  377. radius: 8
  378. color: playMouseArea.pressed ? "#1e40af" : "#2563eb"
  379. Text {
  380. anchors.centerIn: parent
  381. text: "Play Playlist"
  382. color: "white"
  383. font.pixelSize: 14
  384. font.bold: true
  385. }
  386. MouseArea {
  387. id: playMouseArea
  388. anchors.fill: parent
  389. onClicked: {
  390. if (backend) {
  391. console.log("Playing playlist:", selectedPlaylist, "with settings:", {
  392. pauseTime: pauseTime,
  393. clearPattern: clearPattern,
  394. runMode: runMode,
  395. shuffle: shuffle
  396. })
  397. backend.executePlaylist(selectedPlaylist, pauseTime, clearPattern, runMode, shuffle)
  398. // Navigate to execution page
  399. console.log("🎵 Navigating to execution page after playlist start")
  400. if (mainWindow) {
  401. console.log("🎵 Setting shouldNavigateToExecution = true")
  402. mainWindow.shouldNavigateToExecution = true
  403. } else {
  404. console.log("🎵 ERROR: mainWindow is null, cannot navigate")
  405. }
  406. }
  407. }
  408. }
  409. }
  410. // Shuffle toggle button
  411. Rectangle {
  412. Layout.preferredWidth: 60
  413. Layout.preferredHeight: 45
  414. radius: 8
  415. color: shuffle ? "#2563eb" : "#6b7280"
  416. Text {
  417. anchors.centerIn: parent
  418. text: "⇄"
  419. color: "white"
  420. font.pixelSize: 16
  421. }
  422. MouseArea {
  423. id: shuffleMouseArea
  424. anchors.fill: parent
  425. onClicked: {
  426. shuffle = !shuffle
  427. console.log("Shuffle toggled:", shuffle)
  428. }
  429. }
  430. }
  431. }
  432. // Settings section
  433. Rectangle {
  434. Layout.fillWidth: true
  435. Layout.fillHeight: true
  436. Layout.minimumHeight: 250
  437. radius: 10
  438. color: Components.ThemeManager.cardColor
  439. border.color: Components.ThemeManager.borderColor
  440. border.width: 1
  441. ColumnLayout {
  442. anchors.fill: parent
  443. anchors.margins: 15
  444. spacing: 15
  445. Label {
  446. text: "Settings"
  447. font.pixelSize: 14
  448. font.bold: true
  449. color: Components.ThemeManager.textPrimary
  450. }
  451. // Scrollable settings content
  452. ScrollView {
  453. Layout.fillWidth: true
  454. Layout.fillHeight: true
  455. clip: true
  456. ScrollBar.vertical.policy: ScrollBar.AsNeeded
  457. ColumnLayout {
  458. width: parent.width
  459. spacing: 15
  460. // Run mode
  461. Column {
  462. Layout.fillWidth: true
  463. spacing: 8
  464. Label {
  465. text: "Run Mode:"
  466. font.pixelSize: 12
  467. color: Components.ThemeManager.textSecondary
  468. font.bold: true
  469. }
  470. RowLayout {
  471. width: parent.width
  472. spacing: 15
  473. RadioButton {
  474. id: singleModeRadio
  475. text: "Single"
  476. font.pixelSize: 11
  477. checked: true // Default
  478. onClicked: {
  479. runMode = "single"
  480. console.log("Run mode set to:", runMode)
  481. }
  482. contentItem: Text {
  483. text: parent.text
  484. font: parent.font
  485. color: Components.ThemeManager.textPrimary
  486. verticalAlignment: Text.AlignVCenter
  487. leftPadding: parent.indicator.width + parent.spacing
  488. }
  489. }
  490. RadioButton {
  491. id: loopModeRadio
  492. text: "Loop"
  493. font.pixelSize: 11
  494. checked: false
  495. onClicked: {
  496. runMode = "loop"
  497. console.log("Run mode set to:", runMode)
  498. }
  499. contentItem: Text {
  500. text: parent.text
  501. font: parent.font
  502. color: Components.ThemeManager.textPrimary
  503. verticalAlignment: Text.AlignVCenter
  504. leftPadding: parent.indicator.width + parent.spacing
  505. }
  506. }
  507. }
  508. }
  509. // Pause Between Patterns
  510. Column {
  511. Layout.fillWidth: true
  512. spacing: 15
  513. Label {
  514. text: "Pause between patterns:"
  515. font.pixelSize: 12
  516. color: Components.ThemeManager.textSecondary
  517. font.bold: true
  518. }
  519. // Touch-friendly button row for pause options
  520. RowLayout {
  521. id: pauseGrid
  522. Layout.fillWidth: true
  523. spacing: 8
  524. property string currentSelection: backend ? backend.getCurrentPauseOption() : "0s"
  525. // 0s button
  526. Rectangle {
  527. Layout.preferredWidth: 60
  528. Layout.preferredHeight: 40
  529. color: pauseGrid.currentSelection === "0s" ? Components.ThemeManager.selectedBackground : Components.ThemeManager.buttonBackground
  530. border.color: pauseGrid.currentSelection === "0s" ? Components.ThemeManager.selectedBorder : Components.ThemeManager.buttonBorder
  531. border.width: 2
  532. radius: 8
  533. Label {
  534. anchors.centerIn: parent
  535. text: "0s"
  536. font.pixelSize: 12
  537. font.bold: true
  538. color: pauseGrid.currentSelection === "0s" ? "white" : Components.ThemeManager.textPrimary
  539. }
  540. MouseArea {
  541. anchors.fill: parent
  542. onClicked: {
  543. if (backend) {
  544. backend.setPauseByOption("0s")
  545. pauseGrid.currentSelection = "0s"
  546. pauseTime = 0
  547. }
  548. }
  549. }
  550. }
  551. // 1 min button
  552. Rectangle {
  553. Layout.preferredWidth: 60
  554. Layout.preferredHeight: 40
  555. color: pauseGrid.currentSelection === "1 min" ? Components.ThemeManager.selectedBackground : Components.ThemeManager.buttonBackground
  556. border.color: pauseGrid.currentSelection === "1 min" ? Components.ThemeManager.selectedBorder : Components.ThemeManager.buttonBorder
  557. border.width: 2
  558. radius: 8
  559. Label {
  560. anchors.centerIn: parent
  561. text: "1m"
  562. font.pixelSize: 12
  563. font.bold: true
  564. color: pauseGrid.currentSelection === "1 min" ? "white" : Components.ThemeManager.textPrimary
  565. }
  566. MouseArea {
  567. anchors.fill: parent
  568. onClicked: {
  569. if (backend) {
  570. backend.setPauseByOption("1 min")
  571. pauseGrid.currentSelection = "1 min"
  572. pauseTime = 60
  573. }
  574. }
  575. }
  576. }
  577. // 5 min button
  578. Rectangle {
  579. Layout.preferredWidth: 60
  580. Layout.preferredHeight: 40
  581. color: pauseGrid.currentSelection === "5 min" ? Components.ThemeManager.selectedBackground : Components.ThemeManager.buttonBackground
  582. border.color: pauseGrid.currentSelection === "5 min" ? Components.ThemeManager.selectedBorder : Components.ThemeManager.buttonBorder
  583. border.width: 2
  584. radius: 8
  585. Label {
  586. anchors.centerIn: parent
  587. text: "5m"
  588. font.pixelSize: 12
  589. font.bold: true
  590. color: pauseGrid.currentSelection === "5 min" ? "white" : Components.ThemeManager.textPrimary
  591. }
  592. MouseArea {
  593. anchors.fill: parent
  594. onClicked: {
  595. if (backend) {
  596. backend.setPauseByOption("5 min")
  597. pauseGrid.currentSelection = "5 min"
  598. pauseTime = 300
  599. }
  600. }
  601. }
  602. }
  603. // 15 min button
  604. Rectangle {
  605. Layout.preferredWidth: 60
  606. Layout.preferredHeight: 40
  607. color: pauseGrid.currentSelection === "15 min" ? Components.ThemeManager.selectedBackground : Components.ThemeManager.buttonBackground
  608. border.color: pauseGrid.currentSelection === "15 min" ? Components.ThemeManager.selectedBorder : Components.ThemeManager.buttonBorder
  609. border.width: 2
  610. radius: 8
  611. Label {
  612. anchors.centerIn: parent
  613. text: "15m"
  614. font.pixelSize: 12
  615. font.bold: true
  616. color: pauseGrid.currentSelection === "15 min" ? "white" : Components.ThemeManager.textPrimary
  617. }
  618. MouseArea {
  619. anchors.fill: parent
  620. onClicked: {
  621. if (backend) {
  622. backend.setPauseByOption("15 min")
  623. pauseGrid.currentSelection = "15 min"
  624. pauseTime = 900
  625. }
  626. }
  627. }
  628. }
  629. // 30 min button
  630. Rectangle {
  631. Layout.preferredWidth: 60
  632. Layout.preferredHeight: 40
  633. color: pauseGrid.currentSelection === "30 min" ? Components.ThemeManager.selectedBackground : Components.ThemeManager.buttonBackground
  634. border.color: pauseGrid.currentSelection === "30 min" ? Components.ThemeManager.selectedBorder : Components.ThemeManager.buttonBorder
  635. border.width: 2
  636. radius: 8
  637. Label {
  638. anchors.centerIn: parent
  639. text: "30m"
  640. font.pixelSize: 12
  641. font.bold: true
  642. color: pauseGrid.currentSelection === "30 min" ? "white" : Components.ThemeManager.textPrimary
  643. }
  644. MouseArea {
  645. anchors.fill: parent
  646. onClicked: {
  647. if (backend) {
  648. backend.setPauseByOption("30 min")
  649. pauseGrid.currentSelection = "30 min"
  650. pauseTime = 1800
  651. }
  652. }
  653. }
  654. }
  655. // 1 hour button
  656. Rectangle {
  657. Layout.preferredWidth: 60
  658. Layout.preferredHeight: 40
  659. color: pauseGrid.currentSelection === "1 hour" ? Components.ThemeManager.selectedBackground : Components.ThemeManager.buttonBackground
  660. border.color: pauseGrid.currentSelection === "1 hour" ? Components.ThemeManager.selectedBorder : Components.ThemeManager.buttonBorder
  661. border.width: 2
  662. radius: 8
  663. Label {
  664. anchors.centerIn: parent
  665. text: "1h"
  666. font.pixelSize: 12
  667. font.bold: true
  668. color: pauseGrid.currentSelection === "1 hour" ? "white" : Components.ThemeManager.textPrimary
  669. }
  670. MouseArea {
  671. anchors.fill: parent
  672. onClicked: {
  673. if (backend) {
  674. backend.setPauseByOption("1 hour")
  675. pauseGrid.currentSelection = "1 hour"
  676. pauseTime = 3600
  677. }
  678. }
  679. }
  680. }
  681. }
  682. // Second row for longer hour options
  683. RowLayout {
  684. Layout.fillWidth: true
  685. spacing: 8
  686. // 2h button
  687. Rectangle {
  688. Layout.preferredWidth: 60
  689. Layout.preferredHeight: 40
  690. color: pauseGrid.currentSelection === "2 hour" ? Components.ThemeManager.selectedBackground : Components.ThemeManager.buttonBackground
  691. border.color: pauseGrid.currentSelection === "2 hour" ? Components.ThemeManager.selectedBorder : Components.ThemeManager.buttonBorder
  692. border.width: 2
  693. radius: 8
  694. Label {
  695. anchors.centerIn: parent
  696. text: "2h"
  697. font.pixelSize: 12
  698. font.bold: true
  699. color: pauseGrid.currentSelection === "2 hour" ? "white" : Components.ThemeManager.textPrimary
  700. }
  701. MouseArea {
  702. anchors.fill: parent
  703. onClicked: {
  704. if (backend) {
  705. backend.setPauseByOption("2 hour")
  706. pauseGrid.currentSelection = "2 hour"
  707. pauseTime = 7200
  708. }
  709. }
  710. }
  711. }
  712. // 3h button
  713. Rectangle {
  714. Layout.preferredWidth: 60
  715. Layout.preferredHeight: 40
  716. color: pauseGrid.currentSelection === "3 hour" ? Components.ThemeManager.selectedBackground : Components.ThemeManager.buttonBackground
  717. border.color: pauseGrid.currentSelection === "3 hour" ? Components.ThemeManager.selectedBorder : Components.ThemeManager.buttonBorder
  718. border.width: 2
  719. radius: 8
  720. Label {
  721. anchors.centerIn: parent
  722. text: "3h"
  723. font.pixelSize: 12
  724. font.bold: true
  725. color: pauseGrid.currentSelection === "3 hour" ? "white" : Components.ThemeManager.textPrimary
  726. }
  727. MouseArea {
  728. anchors.fill: parent
  729. onClicked: {
  730. if (backend) {
  731. backend.setPauseByOption("3 hour")
  732. pauseGrid.currentSelection = "3 hour"
  733. pauseTime = 10800
  734. }
  735. }
  736. }
  737. }
  738. // 4h button
  739. Rectangle {
  740. Layout.preferredWidth: 60
  741. Layout.preferredHeight: 40
  742. color: pauseGrid.currentSelection === "4 hour" ? Components.ThemeManager.selectedBackground : Components.ThemeManager.buttonBackground
  743. border.color: pauseGrid.currentSelection === "4 hour" ? Components.ThemeManager.selectedBorder : Components.ThemeManager.buttonBorder
  744. border.width: 2
  745. radius: 8
  746. Label {
  747. anchors.centerIn: parent
  748. text: "4h"
  749. font.pixelSize: 12
  750. font.bold: true
  751. color: pauseGrid.currentSelection === "4 hour" ? "white" : Components.ThemeManager.textPrimary
  752. }
  753. MouseArea {
  754. anchors.fill: parent
  755. onClicked: {
  756. if (backend) {
  757. backend.setPauseByOption("4 hour")
  758. pauseGrid.currentSelection = "4 hour"
  759. pauseTime = 14400
  760. }
  761. }
  762. }
  763. }
  764. // 5h button
  765. Rectangle {
  766. Layout.preferredWidth: 60
  767. Layout.preferredHeight: 40
  768. color: pauseGrid.currentSelection === "5 hour" ? Components.ThemeManager.selectedBackground : Components.ThemeManager.buttonBackground
  769. border.color: pauseGrid.currentSelection === "5 hour" ? Components.ThemeManager.selectedBorder : Components.ThemeManager.buttonBorder
  770. border.width: 2
  771. radius: 8
  772. Label {
  773. anchors.centerIn: parent
  774. text: "5h"
  775. font.pixelSize: 12
  776. font.bold: true
  777. color: pauseGrid.currentSelection === "5 hour" ? "white" : Components.ThemeManager.textPrimary
  778. }
  779. MouseArea {
  780. anchors.fill: parent
  781. onClicked: {
  782. if (backend) {
  783. backend.setPauseByOption("5 hour")
  784. pauseGrid.currentSelection = "5 hour"
  785. pauseTime = 18000
  786. }
  787. }
  788. }
  789. }
  790. // 6h button
  791. Rectangle {
  792. Layout.preferredWidth: 60
  793. Layout.preferredHeight: 40
  794. color: pauseGrid.currentSelection === "6 hour" ? Components.ThemeManager.selectedBackground : Components.ThemeManager.buttonBackground
  795. border.color: pauseGrid.currentSelection === "6 hour" ? Components.ThemeManager.selectedBorder : Components.ThemeManager.buttonBorder
  796. border.width: 2
  797. radius: 8
  798. Label {
  799. anchors.centerIn: parent
  800. text: "6h"
  801. font.pixelSize: 12
  802. font.bold: true
  803. color: pauseGrid.currentSelection === "6 hour" ? "white" : Components.ThemeManager.textPrimary
  804. }
  805. MouseArea {
  806. anchors.fill: parent
  807. onClicked: {
  808. if (backend) {
  809. backend.setPauseByOption("6 hour")
  810. pauseGrid.currentSelection = "6 hour"
  811. pauseTime = 21600
  812. }
  813. }
  814. }
  815. }
  816. // 12h button
  817. Rectangle {
  818. Layout.preferredWidth: 60
  819. Layout.preferredHeight: 40
  820. color: pauseGrid.currentSelection === "12 hour" ? Components.ThemeManager.selectedBackground : Components.ThemeManager.buttonBackground
  821. border.color: pauseGrid.currentSelection === "12 hour" ? Components.ThemeManager.selectedBorder : Components.ThemeManager.buttonBorder
  822. border.width: 2
  823. radius: 8
  824. Label {
  825. anchors.centerIn: parent
  826. text: "12h"
  827. font.pixelSize: 12
  828. font.bold: true
  829. color: pauseGrid.currentSelection === "12 hour" ? "white" : Components.ThemeManager.textPrimary
  830. }
  831. MouseArea {
  832. anchors.fill: parent
  833. onClicked: {
  834. if (backend) {
  835. backend.setPauseByOption("12 hour")
  836. pauseGrid.currentSelection = "12 hour"
  837. pauseTime = 43200
  838. }
  839. }
  840. }
  841. }
  842. // Update selection when backend changes
  843. Connections {
  844. target: backend
  845. function onPauseBetweenPatternsChanged(pause) {
  846. if (backend) {
  847. pauseGrid.currentSelection = backend.getCurrentPauseOption()
  848. pauseTime = backend.pauseBetweenPatterns
  849. }
  850. }
  851. }
  852. }
  853. }
  854. // Clear pattern
  855. Column {
  856. Layout.fillWidth: true
  857. spacing: 8
  858. Label {
  859. text: "Clear Pattern:"
  860. font.pixelSize: 12
  861. color: Components.ThemeManager.textSecondary
  862. font.bold: true
  863. }
  864. GridLayout {
  865. width: parent.width
  866. columns: 2
  867. columnSpacing: 10
  868. rowSpacing: 5
  869. RadioButton {
  870. id: adaptiveRadio
  871. text: "Adaptive"
  872. font.pixelSize: 11
  873. checked: true // Default
  874. onClicked: {
  875. clearPattern = "adaptive"
  876. console.log("Clear pattern set to:", clearPattern)
  877. }
  878. contentItem: Text {
  879. text: parent.text
  880. font: parent.font
  881. color: Components.ThemeManager.textPrimary
  882. verticalAlignment: Text.AlignVCenter
  883. leftPadding: parent.indicator.width + parent.spacing
  884. }
  885. }
  886. RadioButton {
  887. id: clearCenterRadio
  888. text: "Clear Center"
  889. font.pixelSize: 11
  890. checked: false
  891. onClicked: {
  892. clearPattern = "clear_center"
  893. console.log("Clear pattern set to:", clearPattern)
  894. }
  895. contentItem: Text {
  896. text: parent.text
  897. font: parent.font
  898. color: Components.ThemeManager.textPrimary
  899. verticalAlignment: Text.AlignVCenter
  900. leftPadding: parent.indicator.width + parent.spacing
  901. }
  902. }
  903. RadioButton {
  904. id: clearEdgeRadio
  905. text: "Clear Edge"
  906. font.pixelSize: 11
  907. checked: false
  908. onClicked: {
  909. clearPattern = "clear_perimeter"
  910. console.log("Clear pattern set to:", clearPattern)
  911. }
  912. contentItem: Text {
  913. text: parent.text
  914. font: parent.font
  915. color: Components.ThemeManager.textPrimary
  916. verticalAlignment: Text.AlignVCenter
  917. leftPadding: parent.indicator.width + parent.spacing
  918. }
  919. }
  920. RadioButton {
  921. id: noneRadio
  922. text: "None"
  923. font.pixelSize: 11
  924. checked: false
  925. onClicked: {
  926. clearPattern = "none"
  927. console.log("Clear pattern set to:", clearPattern)
  928. }
  929. contentItem: Text {
  930. text: parent.text
  931. font: parent.font
  932. color: Components.ThemeManager.textPrimary
  933. verticalAlignment: Text.AlignVCenter
  934. leftPadding: parent.indicator.width + parent.spacing
  935. }
  936. }
  937. }
  938. }
  939. }
  940. }
  941. }
  942. }
  943. }
  944. }
  945. }
  946. }
  947. }
  948. }
  949. }