flea-qml 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (637) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +511 -2
  3. package/THIRD-PARTY-NOTICES.md +29 -0
  4. package/demos/App.java +5 -0
  5. package/demos/Dockerfile +4 -0
  6. package/demos/Main.kt +3 -0
  7. package/demos/Program.cs +1 -0
  8. package/demos/README.md +12 -0
  9. package/demos/app.dart +3 -0
  10. package/demos/app.deb +0 -0
  11. package/demos/app.js +1 -0
  12. package/demos/backup.tar +0 -0
  13. package/demos/budget.xlsx +0 -0
  14. package/demos/build.sh +2 -0
  15. package/demos/bundle.zip +0 -0
  16. package/demos/clip.mp4 +0 -0
  17. package/demos/data.sqlite +0 -0
  18. package/demos/disk.iso +0 -0
  19. package/demos/engine.cpp +5 -0
  20. package/demos/firmware.bin +0 -0
  21. package/demos/flake.nix +4 -0
  22. package/demos/folder/inside.txt +1 -0
  23. package/demos/font.ttf +0 -0
  24. package/demos/index.html +5 -0
  25. package/demos/index.php +2 -0
  26. package/demos/init.lua +1 -0
  27. package/demos/letter.docx +0 -0
  28. package/demos/lib.rs +3 -0
  29. package/demos/main.c +6 -0
  30. package/demos/main.h +3 -0
  31. package/demos/math-and-diagrams.md +200 -0
  32. package/demos/notes.tar.gz +0 -0
  33. package/demos/notes.txt +3 -0
  34. package/demos/photo.png +0 -0
  35. package/demos/program +2 -0
  36. package/demos/report.pdf +32 -0
  37. package/demos/script.py +1 -0
  38. package/demos/server.go +7 -0
  39. package/demos/settings.json +4 -0
  40. package/demos/slides.pptx +0 -0
  41. package/demos/song.mp3 +0 -0
  42. package/demos/style.css +4 -0
  43. package/demos/tool.rb +1 -0
  44. package/demos/types.ts +2 -0
  45. package/docs/pele.md +23 -0
  46. package/docs/protocol.md +3420 -0
  47. package/docs/temml.md +63 -0
  48. package/index.js +107 -0
  49. package/package.json +34 -4
  50. package/src/archive.js +407 -0
  51. package/src/archiveops.js +728 -0
  52. package/src/backend.js +369 -0
  53. package/src/bulkrename.js +95 -0
  54. package/src/clip-host.js +76 -0
  55. package/src/clip.js +462 -0
  56. package/src/code.js +168 -0
  57. package/src/compare.js +74 -0
  58. package/src/create.js +128 -0
  59. package/src/dirsize.js +147 -0
  60. package/src/figure-svg.js +530 -0
  61. package/src/figure-thread.js +23 -0
  62. package/src/figure.js +132 -0
  63. package/src/find.js +55 -0
  64. package/src/flea.js +39 -0
  65. package/src/fsinfo.js +39 -0
  66. package/src/highlight.js +141 -0
  67. package/src/html.js +52 -0
  68. package/src/kinds.js +89 -0
  69. package/src/listing.js +130 -0
  70. package/src/markdown-html.js +317 -0
  71. package/src/mathml.js +186 -0
  72. package/src/menu.js +180 -0
  73. package/src/meta.js +135 -0
  74. package/src/office.js +810 -0
  75. package/src/order.js +100 -0
  76. package/src/peek.js +49 -0
  77. package/src/pele-wrapper.js +695 -0
  78. package/src/permissions.js +180 -0
  79. package/src/places.js +313 -0
  80. package/src/preview-language.js +10 -0
  81. package/src/terminal-server.js +95 -0
  82. package/src/terminal-shell.js +26 -0
  83. package/src/transfer.js +669 -0
  84. package/src/trash-record.js +41 -0
  85. package/src/trash.js +210 -0
  86. package/src/trashbrowse.js +327 -0
  87. package/src/uistate.js +393 -0
  88. package/src/uistore.js +168 -0
  89. package/src/vendor/LICENSES/Apache-2.0.txt +202 -0
  90. package/src/vendor/LICENSES/MIT-katex-2015.txt +27 -0
  91. package/src/vendor/LICENSES/MIT-katex.txt +21 -0
  92. package/src/vendor/LICENSES/MIT-mermaid.txt +21 -0
  93. package/src/vendor/LICENSES/MIT-pele.txt +40 -0
  94. package/src/vendor/LICENSES/MIT-perseus.txt +18 -0
  95. package/src/vendor/LICENSES/MIT-temml.txt +21 -0
  96. package/src/vendor/pele.js +145 -0
  97. package/src/vendor/temml.mjs +14708 -0
  98. package/src/watch.js +98 -0
  99. package/src/wayland/client.js +109 -0
  100. package/src/wayland/protocol.js +55 -0
  101. package/src/wayland/protocols/ext-data-control-v1.xml +276 -0
  102. package/src/wayland/protocols/wayland.xml +3248 -0
  103. package/src/wayland/protocols/wlr-data-control-unstable-v1.xml +278 -0
  104. package/src/wayland/resource-io.js +6 -0
  105. package/src/wayland/socket-discovery.js +26 -0
  106. package/src/wayland/transport-posix.js +120 -0
  107. package/src/wayland/transport-win32.js +11 -0
  108. package/src/wayland/transport.js +3 -0
  109. package/src/wayland/win32-resources.js +80 -0
  110. package/src/wayland/win32-wire.js +62 -0
  111. package/test/archive.test.js +80 -0
  112. package/test/bench-markdown-scroll.mjs +190 -0
  113. package/test/clip-host.test.js +113 -0
  114. package/test/code-preview.test.js +35 -0
  115. package/test/compare-ui-paths.test.js +24 -0
  116. package/test/compare.test.js +54 -0
  117. package/test/delete-trash.test.js +67 -0
  118. package/test/dirsize.test.js +138 -0
  119. package/test/file-ops.test.js +307 -0
  120. package/test/file-url.test.js +24 -0
  121. package/test/find-contents.test.js +161 -0
  122. package/test/find-input.test.js +66 -0
  123. package/test/fixtures/pele-parity.json +1006 -0
  124. package/test/highlight-launcher.test.js +35 -0
  125. package/test/html-preview.test.js +22 -0
  126. package/test/input.test.js +15 -0
  127. package/test/keymap.test.js +26 -0
  128. package/test/language-icons.test.js +36 -0
  129. package/test/launcher.test.js +51 -0
  130. package/test/manual-archive-here-ui.mjs +47 -0
  131. package/test/manual-code-scroll.mjs +28 -0
  132. package/test/manual-column-scroll.mjs +24 -0
  133. package/test/manual-compare-ui.mjs +20 -0
  134. package/test/manual-find-status.mjs +37 -0
  135. package/test/manual-folder-focus.mjs +63 -0
  136. package/test/manual-html-security.mjs +23 -0
  137. package/test/manual-html-ui.mjs +30 -0
  138. package/test/manual-syntax-preview.mjs +26 -0
  139. package/test/manual-terminal-lifecycle.mjs +42 -0
  140. package/test/manual-terminal-navigation.mjs +48 -0
  141. package/test/manual-terminal-ui.mjs +47 -0
  142. package/test/manual-trash-ui.mjs +86 -0
  143. package/test/markdown-diagrams.test.js +93 -0
  144. package/test/markdown-html.test.js +105 -0
  145. package/test/mathml.test.js +92 -0
  146. package/test/menu-transfer.test.js +57 -0
  147. package/test/office-preview.test.js +154 -0
  148. package/test/pele-parity.test.js +28 -0
  149. package/test/places.test.js +134 -0
  150. package/test/preview-keys.test.js +60 -0
  151. package/test/preview-language.test.js +22 -0
  152. package/test/status-filename.test.js +20 -0
  153. package/test/transfer-replace-merge.test.js +187 -0
  154. package/test/trash-address.test.js +23 -0
  155. package/test/trash-view.test.js +37 -0
  156. package/test/trashbrowse.test.js +135 -0
  157. package/ui/AboutFacts.qml +78 -0
  158. package/ui/ArchiveCards.qml +95 -0
  159. package/ui/ArchiveCompressDialog.qml +378 -0
  160. package/ui/ArchiveHereConfirm.qml +127 -0
  161. package/ui/ArchivePasswordDialog.qml +257 -0
  162. package/ui/Backend.qml +775 -0
  163. package/ui/BulkOldNames.qml +47 -0
  164. package/ui/BulkRenameDialog.qml +380 -0
  165. package/ui/CardFrame.qml +67 -0
  166. package/ui/CardScroll.qml +79 -0
  167. package/ui/CheckBox.qml +73 -0
  168. package/ui/ChromeBar.qml +360 -0
  169. package/ui/ChromeButton.qml +131 -0
  170. package/ui/ChromeModes.qml +43 -0
  171. package/ui/CodeLines.qml +256 -0
  172. package/ui/CodeRefusal.qml +52 -0
  173. package/ui/CollideConfirm.qml +147 -0
  174. package/ui/CollideHost.qml +167 -0
  175. package/ui/ColumnPane.qml +525 -0
  176. package/ui/ColumnRow.qml +380 -0
  177. package/ui/ColumnsArea.qml +594 -0
  178. package/ui/ColumnsLanding.qml +147 -0
  179. package/ui/CompareView.qml +321 -0
  180. package/ui/ContextMenu.qml +743 -0
  181. package/ui/ConvertDialog.qml +456 -0
  182. package/ui/CountedWorker.qml +7 -0
  183. package/ui/Crumb.qml +64 -0
  184. package/ui/CrumbDrop.qml +25 -0
  185. package/ui/CsvTable.qml +394 -0
  186. package/ui/CursorMark.qml +41 -0
  187. package/ui/DefaultClaim.qml +130 -0
  188. package/ui/DeviceLock.qml +47 -0
  189. package/ui/DeviceMounts.qml +540 -0
  190. package/ui/DialogButton.qml +150 -0
  191. package/ui/DialogField.qml +147 -0
  192. package/ui/DialogHeader.qml +31 -0
  193. package/ui/DialogScrim.qml +20 -0
  194. package/ui/DialogTitle.qml +37 -0
  195. package/ui/Divider.qml +9 -0
  196. package/ui/DropInto.qml +126 -0
  197. package/ui/DropTarget.qml +35 -0
  198. package/ui/DropboxMark.qml +60 -0
  199. package/ui/EmptyState.qml +150 -0
  200. package/ui/EscapeHint.qml +11 -0
  201. package/ui/FactsTable.qml +54 -0
  202. package/ui/FastScrollHandler.qml +476 -0
  203. package/ui/FatNamesConfirm.qml +157 -0
  204. package/ui/Favourites.qml +143 -0
  205. package/ui/FigureService.qml +120 -0
  206. package/ui/FileDrag.qml +267 -0
  207. package/ui/FilterStrip.qml +133 -0
  208. package/ui/FitMetrics.qml +22 -0
  209. package/ui/FlashDriveRows.qml +137 -0
  210. package/ui/FlashHost.qml +72 -0
  211. package/ui/FlashImageRow.qml +104 -0
  212. package/ui/FlashRunner.qml +119 -0
  213. package/ui/FlashStepRow.qml +172 -0
  214. package/ui/FlashStrip.qml +38 -0
  215. package/ui/FlashView.qml +397 -0
  216. package/ui/FleaMark.qml +88 -0
  217. package/ui/FlyoutFade.qml +23 -0
  218. package/ui/FontPane.qml +170 -0
  219. package/ui/Glass.qml +114 -0
  220. package/ui/GlassTagger.qml +59 -0
  221. package/ui/Glyph.qml +64 -0
  222. package/ui/GlyphSolid.qml +22 -0
  223. package/ui/GridArea.qml +664 -0
  224. package/ui/GridTile.qml +325 -0
  225. package/ui/GvfsBridge.qml +164 -0
  226. package/ui/Header.qml +433 -0
  227. package/ui/HoverTimers.qml +39 -0
  228. package/ui/HtmlClip.qml +30 -0
  229. package/ui/HtmlPane.qml +63 -0
  230. package/ui/HyprlandMark.qml +45 -0
  231. package/ui/Ipc.qml +1005 -0
  232. package/ui/IpcControls.qml +7 -0
  233. package/ui/IpcMenuState.qml +48 -0
  234. package/ui/IpcPreviewState.qml +185 -0
  235. package/ui/JumpPath.qml +51 -0
  236. package/ui/KeymapSheet.qml +561 -0
  237. package/ui/KeymapSheetResult.qml +89 -0
  238. package/ui/KindStack.qml +40 -0
  239. package/ui/LangMark.qml +51 -0
  240. package/ui/LangMarkLoader.qml +26 -0
  241. package/ui/List.qml +480 -0
  242. package/ui/LoadingState.qml +54 -0
  243. package/ui/LocalSend.qml +56 -0
  244. package/ui/LocalSendMark.qml +73 -0
  245. package/ui/MarkdownBlockView.qml +311 -0
  246. package/ui/MarkdownBlocks.qml +35 -0
  247. package/ui/MarkdownFigure.qml +254 -0
  248. package/ui/MarkdownImages.qml +72 -0
  249. package/ui/MarkdownList.qml +81 -0
  250. package/ui/MarkdownMathsText.qml +97 -0
  251. package/ui/MarkdownPane.qml +83 -0
  252. package/ui/MarkdownPictures.qml +41 -0
  253. package/ui/MarkdownQuote.qml +52 -0
  254. package/ui/MarkdownRemote.qml +82 -0
  255. package/ui/MarkdownSource.qml +155 -0
  256. package/ui/MarkdownTable.qml +222 -0
  257. package/ui/MarkdownTableScroll.qml +64 -0
  258. package/ui/MarkdownTableWheel.qml +126 -0
  259. package/ui/MarkdownText.qml +87 -0
  260. package/ui/MarkdownWorker.js +132 -0
  261. package/ui/MatchText.qml +99 -0
  262. package/ui/MediaSession.qml +38 -0
  263. package/ui/MediaSound.qml +26 -0
  264. package/ui/MediaStrip.qml +191 -0
  265. package/ui/MediaTrack.qml +36 -0
  266. package/ui/MediaVolume.qml +54 -0
  267. package/ui/MenuActionDialog.qml +396 -0
  268. package/ui/MenuEdgeFade.qml +24 -0
  269. package/ui/MenuHost.qml +227 -0
  270. package/ui/MenuRow.qml +351 -0
  271. package/ui/MountListing.qml +100 -0
  272. package/ui/NetworkDialog.qml +435 -0
  273. package/ui/NetworkForm.qml +426 -0
  274. package/ui/NetworkMounts.qml +913 -0
  275. package/ui/NetworkPlaces.qml +127 -0
  276. package/ui/OpenWithDialog.qml +613 -0
  277. package/ui/Opener.qml +95 -0
  278. package/ui/Pane.qml +1320 -0
  279. package/ui/PaneMenuActions.qml +527 -0
  280. package/ui/PanePath.qml +90 -0
  281. package/ui/PaneRail.qml +268 -0
  282. package/ui/PaneStates.qml +88 -0
  283. package/ui/PaneSwap.qml +339 -0
  284. package/ui/PaneWire.qml +601 -0
  285. package/ui/ParkedWait.qml +9 -0
  286. package/ui/PathEntry.qml +186 -0
  287. package/ui/PathJump.qml +400 -0
  288. package/ui/PdfViewer.qml +297 -0
  289. package/ui/PermissionsDialog.qml +658 -0
  290. package/ui/PermissionsHeadings.qml +31 -0
  291. package/ui/PhoneMounts.qml +67 -0
  292. package/ui/PickerAnswers.qml +75 -0
  293. package/ui/PickerBox.qml +26 -0
  294. package/ui/PickerChrome.qml +295 -0
  295. package/ui/PickerFilter.qml +97 -0
  296. package/ui/PickerGrid.qml +308 -0
  297. package/ui/PickerHeader.qml +28 -0
  298. package/ui/PickerLifecycle.qml +27 -0
  299. package/ui/PickerList.qml +218 -0
  300. package/ui/PickerListing.qml +149 -0
  301. package/ui/PickerPathBar.qml +127 -0
  302. package/ui/PickerPlaces.qml +189 -0
  303. package/ui/PickerRecent.qml +92 -0
  304. package/ui/PickerSave.qml +101 -0
  305. package/ui/PickerSelection.qml +155 -0
  306. package/ui/PickerWindow.qml +846 -0
  307. package/ui/PowerSectorsReader.qml +10 -0
  308. package/ui/PrebuildDriver.qml +146 -0
  309. package/ui/Preview.qml +1005 -0
  310. package/ui/PreviewAnimation.qml +24 -0
  311. package/ui/PreviewArchive.qml +91 -0
  312. package/ui/PreviewColumn.qml +553 -0
  313. package/ui/PreviewEdge.qml +63 -0
  314. package/ui/PreviewFacts.qml +30 -0
  315. package/ui/PreviewFactsLine.qml +34 -0
  316. package/ui/PreviewHtml.qml +233 -0
  317. package/ui/PreviewImage.qml +253 -0
  318. package/ui/PreviewImagePan.qml +13 -0
  319. package/ui/PreviewImageSharp.qml +32 -0
  320. package/ui/PreviewLines.qml +106 -0
  321. package/ui/PreviewMarkdown.qml +706 -0
  322. package/ui/PreviewMedia.qml +250 -0
  323. package/ui/PreviewPdf.qml +482 -0
  324. package/ui/PreviewScroll.qml +201 -0
  325. package/ui/PreviewSwap.qml +335 -0
  326. package/ui/PreviewText.qml +149 -0
  327. package/ui/ProtocolChip.qml +18 -0
  328. package/ui/QuickLookArchive.qml +41 -0
  329. package/ui/QuickLookBar.qml +103 -0
  330. package/ui/QuickLookPrepare.qml +355 -0
  331. package/ui/QuickLookSwap.qml +10 -0
  332. package/ui/QuickLookWarm.qml +65 -0
  333. package/ui/RailDrop.qml +155 -0
  334. package/ui/RailHeading.qml +19 -0
  335. package/ui/RailPlaces.qml +38 -0
  336. package/ui/RailTrashRow.qml +67 -0
  337. package/ui/RenameField.qml +353 -0
  338. package/ui/RendererRetry.qml +11 -0
  339. package/ui/ResizeHandle.qml +52 -0
  340. package/ui/Reveal.qml +54 -0
  341. package/ui/Row.qml +476 -0
  342. package/ui/RowDrag.qml +213 -0
  343. package/ui/RowDropTarget.qml +27 -0
  344. package/ui/RunCard.qml +286 -0
  345. package/ui/Scripts.qml +65 -0
  346. package/ui/SearchStrip.qml +232 -0
  347. package/ui/SelectionBand.qml +140 -0
  348. package/ui/SelectionPreview.qml +370 -0
  349. package/ui/SettingsFavourite.qml +122 -0
  350. package/ui/SettingsGroup.qml +96 -0
  351. package/ui/SettingsHint.qml +12 -0
  352. package/ui/SettingsMetrics.qml +29 -0
  353. package/ui/SettingsPane.qml +178 -0
  354. package/ui/SettingsPanel.qml +547 -0
  355. package/ui/SettingsRail.qml +128 -0
  356. package/ui/SettingsRow.qml +409 -0
  357. package/ui/SettingsRuler.qml +85 -0
  358. package/ui/SettingsSegment.qml +85 -0
  359. package/ui/ShareBrowser.qml +113 -0
  360. package/ui/ShareLink.qml +67 -0
  361. package/ui/ShelfPins.qml +101 -0
  362. package/ui/Sidebar.qml +728 -0
  363. package/ui/SidebarRow.qml +358 -0
  364. package/ui/Spinner.qml +60 -0
  365. package/ui/StableModel.qml +89 -0
  366. package/ui/StateMessage.qml +84 -0
  367. package/ui/StatusBar.qml +512 -0
  368. package/ui/StatusFileName.qml +27 -0
  369. package/ui/TabBar.qml +673 -0
  370. package/ui/TabDragGeometry.qml +60 -0
  371. package/ui/TagMenuMark.qml +52 -0
  372. package/ui/TagRailSection.qml +53 -0
  373. package/ui/TagSlot.qml +40 -0
  374. package/ui/TagState.qml +150 -0
  375. package/ui/TagSwatch.qml +28 -0
  376. package/ui/Taildrop.qml +86 -0
  377. package/ui/TailscaleMark.qml +50 -0
  378. package/ui/TerminalService.qml +69 -0
  379. package/ui/TerminalTab.qml +48 -0
  380. package/ui/TerminalTabs.qml +27 -0
  381. package/ui/Theme.qml +460 -0
  382. package/ui/ThemeColors.qml +43 -0
  383. package/ui/TransferCard.qml +239 -0
  384. package/ui/TrashConfirm.qml +129 -0
  385. package/ui/TrashDropHandler.qml +11 -0
  386. package/ui/TrashHost.qml +202 -0
  387. package/ui/TrashMonitor.qml +30 -0
  388. package/ui/TrashToolbar.qml +19 -0
  389. package/ui/TrashView.qml +492 -0
  390. package/ui/UnlockDialog.qml +450 -0
  391. package/ui/UnlockHost.qml +206 -0
  392. package/ui/UpdateCheck.qml +97 -0
  393. package/ui/UserDirs.qml +25 -0
  394. package/ui/ViewState.qml +565 -0
  395. package/ui/ViewportScrollBar.qml +195 -0
  396. package/ui/ViewportScrollBars.qml +25 -0
  397. package/ui/WebPreview.qml +33 -0
  398. package/ui/WebPreviewView.qml +26 -0
  399. package/ui/WindowBody.qml +829 -0
  400. package/ui/WindowDrag.qml +35 -0
  401. package/ui/boot/Commons/AudioNodes.qml +50 -0
  402. package/ui/boot/Commons/AudioNodesModel.js +96 -0
  403. package/ui/boot/Commons/Border.qml +243 -0
  404. package/ui/boot/Commons/BorderGeometry.js +373 -0
  405. package/ui/boot/Commons/Color.qml +258 -0
  406. package/ui/boot/Commons/I18n.qml +118 -0
  407. package/ui/boot/Commons/InputDevices.qml +112 -0
  408. package/ui/boot/Commons/InputMethodState.qml +38 -0
  409. package/ui/boot/Commons/IpcRegistry.qml +77 -0
  410. package/ui/boot/Commons/Numbers.js +19 -0
  411. package/ui/boot/Commons/Plural.js +91 -0
  412. package/ui/boot/Commons/ShellIpc.qml +12 -0
  413. package/ui/boot/Commons/Style.qml +561 -0
  414. package/ui/boot/Commons/Translations.qml +100 -0
  415. package/ui/boot/Commons/UntypedInput.qml +152 -0
  416. package/ui/boot/Commons/Util.qml +188 -0
  417. package/ui/boot/Commons/qmldir +13 -0
  418. package/ui/boot/LICENSE-omarchy +20 -0
  419. package/ui/boot/Ui/BackgroundMedia.qml +49 -0
  420. package/ui/boot/Ui/BarIconButton.qml +106 -0
  421. package/ui/boot/Ui/BarIconContent.qml +38 -0
  422. package/ui/boot/Ui/BarIndicator.qml +53 -0
  423. package/ui/boot/Ui/BarWidget.qml +50 -0
  424. package/ui/boot/Ui/BorderOverlay.qml +54 -0
  425. package/ui/boot/Ui/BorderSurface.qml +40 -0
  426. package/ui/boot/Ui/Button.qml +224 -0
  427. package/ui/boot/Ui/ButtonGroup.qml +131 -0
  428. package/ui/boot/Ui/ConfirmDialog.qml +134 -0
  429. package/ui/boot/Ui/CursorSurface.qml +42 -0
  430. package/ui/boot/Ui/Dropdown.qml +245 -0
  431. package/ui/boot/Ui/FilterInput.qml +26 -0
  432. package/ui/boot/Ui/IconContentBounds.qml +141 -0
  433. package/ui/boot/Ui/KeyboardPanel.qml +453 -0
  434. package/ui/boot/Ui/MultiSelect.qml +624 -0
  435. package/ui/boot/Ui/NumberField.qml +86 -0
  436. package/ui/boot/Ui/OpticalGlyph.qml +68 -0
  437. package/ui/boot/Ui/OverlayWindow.qml +102 -0
  438. package/ui/boot/Ui/Panel.qml +60 -0
  439. package/ui/boot/Ui/PanelActionButton.qml +105 -0
  440. package/ui/boot/Ui/PanelController.qml +16 -0
  441. package/ui/boot/Ui/PanelHero.qml +112 -0
  442. package/ui/boot/Ui/PanelKeyCatcher.qml +100 -0
  443. package/ui/boot/Ui/PanelSectionHeader.qml +31 -0
  444. package/ui/boot/Ui/PanelSeparator.qml +19 -0
  445. package/ui/boot/Ui/PanelSlider.qml +156 -0
  446. package/ui/boot/Ui/PanelToolTip.qml +50 -0
  447. package/ui/boot/Ui/PluginBarApi.qml +89 -0
  448. package/ui/boot/Ui/PointerMoveGate.qml +54 -0
  449. package/ui/boot/Ui/PopupCard.qml +181 -0
  450. package/ui/boot/Ui/ScreenMoveRemap.qml +43 -0
  451. package/ui/boot/Ui/SearchableDropdown.qml +354 -0
  452. package/ui/boot/Ui/SizedImage.qml +125 -0
  453. package/ui/boot/Ui/SpeedTestOverlay.qml +412 -0
  454. package/ui/boot/Ui/TextField.qml +58 -0
  455. package/ui/boot/Ui/Toggle.qml +118 -0
  456. package/ui/boot/Ui/ToggleSwitch.qml +115 -0
  457. package/ui/boot/Ui/WidgetButton.qml +172 -0
  458. package/ui/boot/Ui/qmldir +41 -0
  459. package/ui/boot/fleatab.qml +50 -0
  460. package/ui/boot/picker.qml +39 -0
  461. package/ui/boot/shell.qml +131 -0
  462. package/ui/boot/tabtearoff.qml +51 -0
  463. package/ui/js/Anchor.js +379 -0
  464. package/ui/js/AnchorHold.js +162 -0
  465. package/ui/js/Archive.js +157 -0
  466. package/ui/js/ArchiveCard.js +44 -0
  467. package/ui/js/ArchiveOps.js +44 -0
  468. package/ui/js/BackReturn.js +118 -0
  469. package/ui/js/BulkRename.js +100 -0
  470. package/ui/js/Buttons.js +54 -0
  471. package/ui/js/ChromeKeys.js +116 -0
  472. package/ui/js/ClipMarks.js +73 -0
  473. package/ui/js/ClipSelection.js +67 -0
  474. package/ui/js/Clipboard.js +179 -0
  475. package/ui/js/Cloud.js +97 -0
  476. package/ui/js/CodeRuns.js +72 -0
  477. package/ui/js/Collide.js +212 -0
  478. package/ui/js/ColumnFit.js +28 -0
  479. package/ui/js/ColumnMenu.js +111 -0
  480. package/ui/js/Columns.js +298 -0
  481. package/ui/js/ColumnsCarry.js +103 -0
  482. package/ui/js/Compare.js +74 -0
  483. package/ui/js/Contrast.js +157 -0
  484. package/ui/js/ControlReader.js +42 -0
  485. package/ui/js/Convert.js +52 -0
  486. package/ui/js/CopyAs.js +52 -0
  487. package/ui/js/Crumbs.js +178 -0
  488. package/ui/js/Csv.js +231 -0
  489. package/ui/js/Density.js +44 -0
  490. package/ui/js/Devices.js +440 -0
  491. package/ui/js/DirSizes.js +180 -0
  492. package/ui/js/Drag.js +360 -0
  493. package/ui/js/DragOut.js +166 -0
  494. package/ui/js/DropDev.js +52 -0
  495. package/ui/js/Dropbox.js +41 -0
  496. package/ui/js/Eject.js +217 -0
  497. package/ui/js/Errors.js +188 -0
  498. package/ui/js/ExtThumbs.js +115 -0
  499. package/ui/js/Facts.js +402 -0
  500. package/ui/js/FigureDate.js +14 -0
  501. package/ui/js/Filter.js +285 -0
  502. package/ui/js/Find.js +46 -0
  503. package/ui/js/Flash.js +184 -0
  504. package/ui/js/FlashCard.js +79 -0
  505. package/ui/js/FlashEndings.js +125 -0
  506. package/ui/js/FlashPane.js +116 -0
  507. package/ui/js/FleaBin.js +12 -0
  508. package/ui/js/Focus.js +504 -0
  509. package/ui/js/FolderSorts.js +108 -0
  510. package/ui/js/FolderViews.js +44 -0
  511. package/ui/js/Format.js +314 -0
  512. package/ui/js/Fuzzy.js +141 -0
  513. package/ui/js/GlassTag.js +72 -0
  514. package/ui/js/Grid.js +33 -0
  515. package/ui/js/GridGeometry.js +90 -0
  516. package/ui/js/GridNames.js +153 -0
  517. package/ui/js/GvfsBridge.js +200 -0
  518. package/ui/js/HostClipboard.js +29 -0
  519. package/ui/js/Icons.js +218 -0
  520. package/ui/js/Input.js +50 -0
  521. package/ui/js/Jump.js +200 -0
  522. package/ui/js/KeyName.js +64 -0
  523. package/ui/js/Keymap.js +401 -0
  524. package/ui/js/Kinds.js +164 -0
  525. package/ui/js/LICENSES/ISC-lucide.txt +43 -0
  526. package/ui/js/LangMarkPaths.js +47 -0
  527. package/ui/js/LangMarks.js +120 -0
  528. package/ui/js/Lists.js +11 -0
  529. package/ui/js/LocalSend.js +39 -0
  530. package/ui/js/LockedMenu.js +63 -0
  531. package/ui/js/MakeDefault.js +186 -0
  532. package/ui/js/MarkBox.js +7 -0
  533. package/ui/js/Markdown.js +119 -0
  534. package/ui/js/MarkdownLists.js +86 -0
  535. package/ui/js/MarkdownMaths.js +58 -0
  536. package/ui/js/MarkdownPictures.js +32 -0
  537. package/ui/js/MarkdownPrepared.js +139 -0
  538. package/ui/js/MarkdownTableFit.js +34 -0
  539. package/ui/js/Marks.js +148 -0
  540. package/ui/js/Marquee.js +96 -0
  541. package/ui/js/Match.js +93 -0
  542. package/ui/js/Material.js +109 -0
  543. package/ui/js/MdBlocks.js +437 -0
  544. package/ui/js/MdBreak.js +71 -0
  545. package/ui/js/MdChunks.js +70 -0
  546. package/ui/js/MdContainer.js +137 -0
  547. package/ui/js/MdDocument.js +337 -0
  548. package/ui/js/MdEmph.js +97 -0
  549. package/ui/js/MdEntity.js +108 -0
  550. package/ui/js/MdEntityTable.js +223 -0
  551. package/ui/js/MdEscape.js +59 -0
  552. package/ui/js/MdFront.js +37 -0
  553. package/ui/js/MdHold.js +32 -0
  554. package/ui/js/MdHtml.js +307 -0
  555. package/ui/js/MdHtmlBlock.js +290 -0
  556. package/ui/js/MdHtmlHeading.js +53 -0
  557. package/ui/js/MdHtmlImage.js +179 -0
  558. package/ui/js/MdInline.js +154 -0
  559. package/ui/js/MdItems.js +212 -0
  560. package/ui/js/MdLeaf.js +309 -0
  561. package/ui/js/MdLink.js +196 -0
  562. package/ui/js/MdMath.js +67 -0
  563. package/ui/js/MdParagraphs.js +138 -0
  564. package/ui/js/MdRefs.js +232 -0
  565. package/ui/js/MdResolve.js +226 -0
  566. package/ui/js/MdRun.js +300 -0
  567. package/ui/js/MdUrl.js +226 -0
  568. package/ui/js/Menu.js +514 -0
  569. package/ui/js/MenuContext.js +85 -0
  570. package/ui/js/MenuFit.js +13 -0
  571. package/ui/js/MenuRefresh.js +74 -0
  572. package/ui/js/MenuWheel.js +35 -0
  573. package/ui/js/Messages.js +186 -0
  574. package/ui/js/Motion.js +16 -0
  575. package/ui/js/Mounts.js +320 -0
  576. package/ui/js/MouseNav.js +13 -0
  577. package/ui/js/Nav.js +329 -0
  578. package/ui/js/NetFs.js +26 -0
  579. package/ui/js/OpenWith.js +83 -0
  580. package/ui/js/Ops.js +585 -0
  581. package/ui/js/Palette.js +33 -0
  582. package/ui/js/PathBar.js +260 -0
  583. package/ui/js/Permissions.js +179 -0
  584. package/ui/js/Phones.js +112 -0
  585. package/ui/js/Picker.js +353 -0
  586. package/ui/js/PlaceMenu.js +96 -0
  587. package/ui/js/Places.js +265 -0
  588. package/ui/js/PreviewAsk.js +21 -0
  589. package/ui/js/PreviewKeys.js +155 -0
  590. package/ui/js/PreviewSettle.js +29 -0
  591. package/ui/js/PreviewSwap.js +101 -0
  592. package/ui/js/PropertyFacts.js +144 -0
  593. package/ui/js/Protocols.js +296 -0
  594. package/ui/js/QuickLookKinds.js +27 -0
  595. package/ui/js/QuickLookRect.js +24 -0
  596. package/ui/js/RailDrop.js +51 -0
  597. package/ui/js/RailKeys.js +87 -0
  598. package/ui/js/RailMenu.js +133 -0
  599. package/ui/js/Recent.js +135 -0
  600. package/ui/js/RecentMode.js +156 -0
  601. package/ui/js/Reload.js +60 -0
  602. package/ui/js/Renderer.js +9 -0
  603. package/ui/js/RunFile.js +143 -0
  604. package/ui/js/Scripts.js +28 -0
  605. package/ui/js/Scroll.js +304 -0
  606. package/ui/js/ScrollOff.js +69 -0
  607. package/ui/js/Search.js +478 -0
  608. package/ui/js/Selection.js +97 -0
  609. package/ui/js/Settings.js +476 -0
  610. package/ui/js/SettingsAbout.js +97 -0
  611. package/ui/js/SettingsShelf.js +52 -0
  612. package/ui/js/SheetKeys.js +42 -0
  613. package/ui/js/SheetQuery.js +281 -0
  614. package/ui/js/ShelfPile.js +27 -0
  615. package/ui/js/SlowClick.js +53 -0
  616. package/ui/js/SlowOp.js +6 -0
  617. package/ui/js/Sort.js +134 -0
  618. package/ui/js/Startup.js +63 -0
  619. package/ui/js/StateWords.js +17 -0
  620. package/ui/js/Status.js +238 -0
  621. package/ui/js/Swap.js +166 -0
  622. package/ui/js/TabMove.js +39 -0
  623. package/ui/js/Tabs.js +751 -0
  624. package/ui/js/Tags.js +134 -0
  625. package/ui/js/Taildrop.js +128 -0
  626. package/ui/js/Tap.js +180 -0
  627. package/ui/js/TextSize.js +107 -0
  628. package/ui/js/Thumbs.js +158 -0
  629. package/ui/js/Transfer.js +172 -0
  630. package/ui/js/Trash.js +84 -0
  631. package/ui/js/TrashDates.js +47 -0
  632. package/ui/js/TrashDrop.js +64 -0
  633. package/ui/js/UiState.js +438 -0
  634. package/ui/js/Unlock.js +152 -0
  635. package/ui/js/Update.js +130 -0
  636. package/ui/js/UserDirs.js +56 -0
  637. package/ui/qmldir +230 -0
@@ -0,0 +1,172 @@
1
+ import QtQuick
2
+ import qs.Commons
3
+ import "." as Flea
4
+ import "js/Flash.js" as Flash
5
+ import "js/Transfer.js" as Transfer
6
+
7
+ // The FLASH step: one 37 px row with the alert mark, erase line and action, then the running bar and the ending row.
8
+ Column {
9
+ id: root
10
+ property var transfer: null
11
+ property real rate: 0
12
+ property var words: ({ erase: "", action: "" })
13
+ property bool live: false
14
+ property bool running: false
15
+ property var ending: null
16
+ property bool ejected: false
17
+ property bool cursor: false
18
+ property bool focused: true
19
+ signal pressFlash()
20
+ signal pressCancel()
21
+ signal pressEnd()
22
+ readonly property var flashItem: flashButton
23
+ readonly property var cancelItem: cancelButton
24
+ readonly property var endItem: endButton
25
+ width: 0
26
+ // The running bar takes the transfer card's recipe: half a caption thick, a quarter-ink track.
27
+ readonly property int barHeight: Math.round(Theme.font.caption / 2)
28
+ readonly property real trackOpacity: 0.25
29
+ Text {
30
+ x: Theme.spacing.rowPaddingX
31
+ // A later section opens a panel gap under the one above, as the rail's FAVORITES does.
32
+ topPadding: Math.round(Style.spacing.panelGap * Theme.sizeRatio) + Math.ceil(font.pixelSize * 0.15)
33
+ bottomPadding: Theme.spacing.gap
34
+ text: "FLASH"
35
+ color: Theme.color.muted
36
+ font.family: Theme.font.family
37
+ font.pixelSize: Theme.font.caption
38
+ font.letterSpacing: 1
39
+ textFormat: Text.PlainText
40
+ }
41
+ Rectangle {
42
+ width: root.width
43
+ height: Theme.rowHeight
44
+ // The cursor uses accent ink, as every listing row does; the greyed Flash row only dims.
45
+ color: root.cursor ? (root.focused ? Style.selectedAccentFill : "transparent") : "transparent"
46
+ opacity: !root.running && root.ending === null && !root.live ? Theme.disabledOpacity : 1
47
+ Rectangle {
48
+ visible: root.cursor
49
+ width: Theme.spacing.hairline * 2
50
+ height: parent.height
51
+ color: root.focused ? Theme.color.accent : Theme.color.mutedFrame
52
+ }
53
+ Row {
54
+ anchors.fill: parent
55
+ anchors.leftMargin: Theme.spacing.rowPaddingX
56
+ anchors.rightMargin: Theme.spacing.rowPaddingX
57
+ spacing: Theme.spacing.gap
58
+ Flea.Glyph {
59
+ width: Theme.markSize
60
+ height: parent.height
61
+ visible: !root.running && root.ending === null
62
+ name: "alert"
63
+ color: Theme.color.error
64
+ }
65
+ Flea.Spinner {
66
+ width: Theme.markSize
67
+ height: parent.height
68
+ visible: root.running
69
+ color: Theme.color.mutedFrame
70
+ }
71
+ Flea.Glyph {
72
+ width: Theme.markSize
73
+ height: parent.height
74
+ visible: root.ending !== null
75
+ name: root.ending ? root.ending.mark : "check"
76
+ color: root.ending && root.ending.role === "error" ? Theme.color.error
77
+ : root.ending && root.ending.role === "foreground" ? Theme.color.foreground : Theme.color.mutedFrame
78
+ }
79
+ Text {
80
+ width: Math.max(0, parent.width - Theme.markSize - flashControl.width - 2 * parent.spacing)
81
+ anchors.verticalCenter: parent.verticalCenter
82
+ text: root.running ? Transfer.head(root.transfer)
83
+ : root.ending ? root.ending.headline : root.words.erase
84
+ textFormat: Text.PlainText
85
+ elide: Text.ElideRight
86
+ color: Flash.stepRole(root.running, root.ending) === "error" ? Theme.color.error : Theme.color.foreground
87
+ font { family: Theme.font.family; pixelSize: Theme.font.body }
88
+ }
89
+ Item {
90
+ id: flashControl
91
+ width: Math.max(flashButton.implicitWidth, cancelButton.implicitWidth, endButton.implicitWidth)
92
+ height: parent.height
93
+ Flea.DialogButton {
94
+ id: flashButton
95
+ anchors.verticalCenter: parent.verticalCenter
96
+ visible: !root.running && root.ending === null
97
+ label: root.words.action
98
+ primary: true
99
+ available: root.live
100
+ onActivated: root.pressFlash()
101
+ }
102
+ Flea.DialogButton {
103
+ id: cancelButton
104
+ anchors.verticalCenter: parent.verticalCenter
105
+ visible: root.running
106
+ label: "Cancel"
107
+ available: Transfer.cancelEnabled(root.transfer)
108
+ onActivated: root.pressCancel()
109
+ }
110
+ Flea.DialogButton {
111
+ id: endButton
112
+ anchors.verticalCenter: parent.verticalCenter
113
+ visible: !root.running && root.ending !== null && (root.ending.eject || root.ending.flashBack) && !root.ejected
114
+ label: root.ending && root.ending.flashBack ? root.words.action : "Eject"
115
+ primary: root.ending ? root.ending.flashBack : false
116
+ available: root.ending && root.ending.flashBack ? root.live : true
117
+ onActivated: root.pressEnd()
118
+ }
119
+ }
120
+ }
121
+ }
122
+ // The running step's own lines under the label column, the bar and then the byte line.
123
+ Column {
124
+ visible: root.running
125
+ x: Theme.spacing.rowPaddingX + Theme.markSize + Theme.spacing.gap
126
+ width: root.width - x - Theme.spacing.rowPaddingX - Theme.column.size
127
+ topPadding: Theme.spacing.rowPaddingY
128
+ spacing: root.barHeight
129
+ // The fill is a sibling of the track and not its child, because opacity multiplies down into children.
130
+ Item {
131
+ width: parent.width
132
+ height: root.barHeight
133
+ Rectangle {
134
+ anchors.fill: parent
135
+ color: Theme.color.mutedFrame
136
+ opacity: root.trackOpacity
137
+ }
138
+ Rectangle {
139
+ width: parent.width * Transfer.fraction(root.transfer)
140
+ height: parent.height
141
+ color: Theme.color.accentFrame
142
+ }
143
+ }
144
+ Row {
145
+ id: byteLine
146
+ readonly property var parts: Transfer.byteParts(root.transfer, root.rate)
147
+ Repeater {
148
+ model: byteLine.parts
149
+ delegate: Text {
150
+ required property var modelData
151
+ text: modelData.text
152
+ color: modelData.figure ? Theme.color.foreground : Theme.color.muted
153
+ font.family: Theme.font.family
154
+ font.pixelSize: Theme.font.caption
155
+ textFormat: Text.PlainText
156
+ }
157
+ }
158
+ }
159
+ }
160
+ Text {
161
+ visible: root.ending !== null && root.ending.hint.length > 0
162
+ x: Theme.spacing.rowPaddingX + Theme.markSize + Theme.spacing.gap
163
+ topPadding: Theme.spacing.rowPaddingY
164
+ bottomPadding: Theme.spacing.rowPaddingY
165
+ width: root.width - x - Theme.spacing.rowPaddingX
166
+ wrapMode: Text.Wrap
167
+ text: root.ending ? root.ending.hint : ""
168
+ color: Theme.color.muted
169
+ font { family: Theme.font.family; pixelSize: Theme.font.caption }
170
+ textFormat: Text.PlainText
171
+ }
172
+ }
@@ -0,0 +1,38 @@
1
+ import QtQuick
2
+ import "." as Flea
3
+
4
+ // The flasher's strip: Back, an unavailable Up and the title; every exit leaves through the view's close.
5
+ Rectangle {
6
+ id: root
7
+ signal back()
8
+ width: 0
9
+ height: Theme.chromeHeight
10
+ color: Theme.color.surface
11
+ Row {
12
+ anchors.fill: parent
13
+ anchors.leftMargin: Theme.spacing.rowPaddingX
14
+ anchors.rightMargin: Theme.spacing.rowPaddingX
15
+ spacing: Theme.spacing.gap
16
+ Flea.ChromeButton {
17
+ ruleRows: Theme.spacing.hairline
18
+ glyph: "arrow-left"
19
+ onActivated: root.back()
20
+ }
21
+ Flea.ChromeButton {
22
+ ruleRows: Theme.spacing.hairline
23
+ glyph: "arrow-up"
24
+ accessName: "Up unavailable in Flash"
25
+ enabled: false
26
+ Accessible.ignored: false
27
+ }
28
+ Text {
29
+ anchors.verticalCenter: parent.verticalCenter
30
+ text: "Flash image"
31
+ textFormat: Text.PlainText
32
+ elide: Text.ElideRight
33
+ color: Theme.color.foreground
34
+ font { family: Theme.font.family; pixelSize: Theme.font.caption }
35
+ }
36
+ }
37
+ Rectangle { anchors.bottom: parent.bottom; width: parent.width; height: Theme.spacing.hairline; color: Theme.color.foreground; opacity: 0.12 }
38
+ }
@@ -0,0 +1,397 @@
1
+ import QtQuick
2
+ import Quickshell
3
+ import Quickshell.Io
4
+ import "." as Flea
5
+ import "js/Flash.js" as Flash
6
+ import "js/FlashPane.js" as FlashPane
7
+ import "js/Keymap.js" as Keymap
8
+ import "js/Ops.js" as Ops
9
+
10
+ // Flash image swaps the listing like Trash does; Esc, Back and Backspace leave the pane and never cancel a flash.
11
+ FocusScope {
12
+ id: root
13
+ required property var pane
14
+ property var statusBar: null
15
+ property bool opened: false
16
+ // The image under test, or null before the picker names one.
17
+ property var image: null
18
+ // A rail volume's device path waiting for the drive list to name its disk.
19
+ property string pendingDrive: ""
20
+ property var drives: []
21
+ property bool drivesReady: false
22
+ // The chosen drive's row, held by identity so a poll that reorders the list never retargets Flash or Eject.
23
+ property var chosen: null
24
+ // Set once this opening holds a drive, so a choice that left stays empty instead of falling to the one fitting drive left.
25
+ property bool held: false
26
+ readonly property int selected: FlashPane.indexOf(root.drives, root.chosen)
27
+ property int cursor: 0
28
+ property int requestId: 0
29
+ property bool ejected: false
30
+ // The flash's own run, answered by the backend; the view owns the cursor and the rows.
31
+ readonly property var transfer: runner.transfer
32
+ readonly property bool running: runner.running
33
+ readonly property var ending: runner.ending
34
+ readonly property real rate: runner.rate
35
+ readonly property int driveCount: root.drives.length
36
+ readonly property var chosenDrive: root.selected >= 0 && root.selected < root.drives.length ? root.drives[root.selected] : null
37
+ readonly property int flashRow: Flash.flashPos(root.drives.length)
38
+ readonly property bool imageOk: root.image !== null && root.image.refused !== true
39
+ readonly property bool live: Flash.flashLive(root.imageOk, root.chosenDrive)
40
+ readonly property var words: Flash.flashWords(root.imageOk, root.chosenDrive, root.drives)
41
+ signal backRequested()
42
+ signal focusRailRequested()
43
+ anchors.fill: parent
44
+ visible: opened
45
+ // The seam's own handles onto the step's controls, so a driven case clicks what it named.
46
+ readonly property var flashItem: stepRow.flashItem
47
+ readonly property var cancelItem: stepRow.cancelItem
48
+ readonly property var endItem: stepRow.endItem
49
+
50
+ function open() {
51
+ // Reopening onto a running flash shows it, never restarts it, and takes its card back from the pane.
52
+ if (runner.running) {
53
+ FlashPane.reclaim(root.pane)
54
+ root.opened = true
55
+ root.forceActiveFocus()
56
+ return
57
+ }
58
+ runner.reset()
59
+ root.ejected = false
60
+ root.opened = true
61
+ root.drives = []
62
+ root.drivesReady = false
63
+ root.forceActiveFocus()
64
+ }
65
+
66
+ function openWithImage(path) {
67
+ if (runner.running)
68
+ return root.open()
69
+ root.image = { path: path, kind: "", bytes: 0, unpacked: 0, known: false, member: "", refused: false }
70
+ root.pendingDrive = ""
71
+ root.chosen = null
72
+ root.cursor = 0
73
+ root.open()
74
+ root.pane.backend.flashImage(path)
75
+ root.pane.backend.flashTargets(path)
76
+ }
77
+
78
+ function openWithDrive(device) {
79
+ if (runner.running)
80
+ return root.open()
81
+ root.pendingDrive = device
82
+ root.chosen = null
83
+ root.cursor = 0
84
+ root.open()
85
+ if (root.image)
86
+ root.pane.backend.flashImage(root.image.path)
87
+ root.pane.backend.flashTargets(root.image ? root.image.path : "")
88
+ }
89
+
90
+ function close() {
91
+ if (!root.opened)
92
+ return
93
+ root.opened = false
94
+ // After Back the running flash joins the pane's transfer the way a copy's does.
95
+ if (root.running) {
96
+ root.pane.transfer = root.transfer
97
+ root.pane.sticky(Ops.progressLine(root.transfer))
98
+ }
99
+ root.backRequested()
100
+ }
101
+
102
+ function chooseImage() {
103
+ if (chooser.running || root.running)
104
+ return
105
+ var home = Quickshell.env("HOME") || ""
106
+ chooser.command = [Quickshell.env("FLEA_BIN") || "flea", "flash", "choose", home + "/Downloads"]
107
+ chooser.running = true
108
+ }
109
+
110
+ function pressFlash() {
111
+ if (runner.pressSent || !root.live || root.running)
112
+ return
113
+ var drive = root.chosenDrive
114
+ root.requestId += 1
115
+ runner.pressSent = true
116
+ runner.pendingId = root.requestId
117
+ root.pane.backend.flash(root.requestId, root.image.path, drive.dev, drive.seq, drive.serial, drive.bytes)
118
+ }
119
+
120
+ function pressCancel() {
121
+ if (!root.running)
122
+ return
123
+ root.pane.backend.flashCancel(root.transfer.id)
124
+ }
125
+
126
+ function ejectChosen() {
127
+ var drive = root.chosenDrive
128
+ if (!drive || root.running || root.ejected)
129
+ return
130
+ root.pane.backend.flashEject(drive.dev, drive.seq)
131
+ }
132
+
133
+ function cursorDrive() {
134
+ return root.cursor > 0 && root.cursor <= root.drives.length ? root.cursor - 1 : -1
135
+ }
136
+
137
+ function moveCursor(delta) {
138
+ // While a flash runs the cursor stays between the drive being flashed and Cancel.
139
+ if (root.running) {
140
+ root.cursor = root.cursor === root.flashRow ? root.selected + 1 : root.flashRow
141
+ root.parkFocus()
142
+ return
143
+ }
144
+ root.cursor = Flash.step(root.cursor, delta, root.drives, root.image !== null, true)
145
+ root.chosen = FlashPane.chooseKept(root.cursor, root.drives, root.chosen)
146
+ root.parkFocus()
147
+ }
148
+
149
+ function parkFocus() {
150
+ if (!root.opened)
151
+ return
152
+ // After Eject no button is drawn, so the keyboard rests on the pane itself.
153
+ if (root.ejected) {
154
+ root.forceActiveFocus()
155
+ return
156
+ }
157
+ if (root.cursor === root.flashRow && !root.running) {
158
+ if (root.ending && (root.ending.flashBack || root.ending.eject) && stepRow.endItem)
159
+ stepRow.endItem.forceActiveFocus()
160
+ else if (!root.ending && stepRow.flashItem)
161
+ stepRow.flashItem.forceActiveFocus()
162
+ else
163
+ root.forceActiveFocus()
164
+ } else if (root.cursor === root.flashRow && stepRow.cancelItem) {
165
+ stepRow.cancelItem.forceActiveFocus()
166
+ } else {
167
+ root.forceActiveFocus()
168
+ }
169
+ }
170
+
171
+ // A focused button owns Enter and Space itself, so the scope stands aside for those keys.
172
+ function buttonFocused() {
173
+ return (stepRow.flashItem && stepRow.flashItem.activeFocus)
174
+ || (stepRow.cancelItem && stepRow.cancelItem.activeFocus)
175
+ || (stepRow.endItem && stepRow.endItem.activeFocus)
176
+ }
177
+
178
+ // The ending row's own action: Eject where one is offered, Flash again under a failure.
179
+ function pressEnd() {
180
+ if (root.ending && root.ending.flashBack)
181
+ root.pressFlash()
182
+ else
183
+ root.ejectChosen()
184
+ }
185
+
186
+ function contextPress() {
187
+ var atDrive = root.cursorDrive()
188
+ if (root.running) {
189
+ if (root.cursor === root.flashRow)
190
+ root.pressCancel()
191
+ return
192
+ }
193
+ if (root.ending !== null) {
194
+ if (root.cursor === root.flashRow) {
195
+ if (root.ending.eject)
196
+ root.ejectChosen()
197
+ else if (root.ending.flashBack)
198
+ root.pressFlash()
199
+ } else if (root.cursor === 0) {
200
+ root.chooseImage()
201
+ } else if (atDrive >= 0) {
202
+ root.chosen = root.drives[atDrive]
203
+ root.cursor = root.flashRow
204
+ root.parkFocus()
205
+ }
206
+ return
207
+ }
208
+ if (root.cursor === 0) {
209
+ root.chooseImage()
210
+ return
211
+ }
212
+ if (atDrive >= 0) {
213
+ root.chosen = root.drives[atDrive]
214
+ root.cursor = root.flashRow
215
+ root.parkFocus()
216
+ return
217
+ }
218
+ if (root.cursor === root.flashRow)
219
+ root.pressFlash()
220
+ }
221
+
222
+ function receiveImage(message) {
223
+ if (!root.opened && !root.running)
224
+ return
225
+ var image = Flash.imageFrom(root.image, message)
226
+ if (image)
227
+ root.image = image
228
+ }
229
+
230
+ function receiveTargets(message) {
231
+ if (!root.opened && !root.running)
232
+ return
233
+ var rows = message.drives || []
234
+ var was = root.drives
235
+ var first = !root.drivesReady
236
+ root.drives = rows
237
+ root.drivesReady = true
238
+ if (root.running)
239
+ return
240
+ // A fitting drive plugged in after Eject brings the Flash row back.
241
+ if (root.ejected) {
242
+ if (rows.filter(function (drive) { return Flash.fits(drive) }).length === 0)
243
+ return
244
+ root.ejected = false
245
+ runner.ending = null
246
+ }
247
+ var next = FlashPane.reconcile({ chosen: root.chosen, cursor: root.cursor, drives: was, first: first,
248
+ held: root.held, pendingDisk: root.pendingDrive }, rows)
249
+ FlashPane.land(root, next)
250
+ if (next.moved)
251
+ root.parkFocus()
252
+ }
253
+
254
+ function startTransfer(id, total, known) {
255
+ var drive = root.chosenDrive
256
+ var label = drive ? Flash.driveName(drive, root.drives) : ""
257
+ runner.startTransfer(id, total, known, root.image ? Flash.leaf(root.image.path) : "", label, root.opened)
258
+ root.cursor = root.flashRow
259
+ root.parkFocus()
260
+ }
261
+
262
+ function progressTransfer(id, phase, bytes, total, permille) {
263
+ runner.progressTransfer(id, phase, bytes, total, permille, root.opened)
264
+ }
265
+
266
+ function finishTransfer(message) {
267
+ var imageName = root.image ? Flash.leaf(root.image.path) : ""
268
+ var landed = runner.finishTransfer(message, imageName, root.transfer.drive,
269
+ root.chosen ? root.chosen.bytes : 0, root.opened)
270
+ if (landed === "refused")
271
+ root.pane.backend.flashImage(root.image ? root.image.path : "")
272
+ else if (landed) {
273
+ root.cursor = root.flashRow
274
+ root.parkFocus()
275
+ }
276
+ }
277
+
278
+ function finishEject(message) {
279
+ var drive = root.chosenDrive
280
+ runner.finishEject(message, drive ? Flash.driveName(drive, root.drives) : "")
281
+ if (message.ok === true) {
282
+ root.ejected = true
283
+ root.parkFocus()
284
+ }
285
+ }
286
+
287
+ Keys.onPressed: function (event) {
288
+ var action = Keymap.lookup(event.key, event.text, event.modifiers, "listing", "gui")
289
+ var unmodified = (event.modifiers & (Qt.ControlModifier | Qt.ShiftModifier | Qt.AltModifier | Qt.MetaModifier)) === 0
290
+ if (action === "escape" && root.statusBar && root.statusBar.escapePressed()) { event.accepted = true; return }
291
+ if (action === "escape" || (event.key === Qt.Key_Backspace && unmodified)) root.close()
292
+ else if (action === "cursorDown") root.moveCursor(1)
293
+ else if (action === "cursorUp") root.moveCursor(-1)
294
+ else if (action === "eject") root.ejectChosen()
295
+ else if (action === "focusNext") root.focusRailRequested()
296
+ else if (action === "open" || (event.key === Qt.Key_Space && unmodified)) {
297
+ if (root.buttonFocused()) { event.accepted = true; return }
298
+ // A held Enter stops on Flash instead of pressing it: only a fresh press confirms.
299
+ if (event.isAutoRepeat && root.cursor === root.flashRow && root.ending === null) { event.accepted = true; return }
300
+ root.contextPress()
301
+ }
302
+ event.accepted = true
303
+ }
304
+
305
+ Process {
306
+ id: chooser
307
+ stdout: StdioCollector { id: chosenText }
308
+ // A chooser that never answers is the backend's refusal, so the pane keeps its drives.
309
+ onExited: function (exitCode, exitStatus) {
310
+ if (exitCode !== 0)
311
+ return
312
+ var path = chosenText.text.trim()
313
+ if (path.length > 0)
314
+ root.openWithImage(path)
315
+ }
316
+ }
317
+
318
+ Connections {
319
+ target: root.pane.backend
320
+ function onFlashImageResult(message) { root.receiveImage(message) }
321
+ function onFlashTargetsResult(message) { root.receiveTargets(message) }
322
+ function onFlashStartedLine(id, total, known) { root.startTransfer(id, total, known) }
323
+ function onFlashProgressLine(id, phase, bytes, total, permille) { root.progressTransfer(id, phase, bytes, total, permille) }
324
+ function onFlashDoneLine(message) { root.finishTransfer(message) }
325
+ function onFlashEjectLine(message) { root.finishEject(message) }
326
+ }
327
+
328
+ // A fitting drive plugged in after Eject brings the Flash row back; the rail's own poll period is the tick.
329
+ readonly property int pollMs: 5000
330
+ Timer {
331
+ interval: root.pollMs
332
+ repeat: true
333
+ running: root.opened && !root.running
334
+ onTriggered: root.pane.backend.flashTargets(root.image ? root.image.path : "")
335
+ }
336
+
337
+ // The flash's own run, answered by the backend; the view owns the cursor and the rows.
338
+ Flea.FlashRunner {
339
+ id: runner
340
+ pane: root.pane
341
+ }
342
+
343
+ Rectangle { anchors.fill: parent; color: Theme.color.background }
344
+
345
+ Column {
346
+ anchors.fill: parent
347
+ spacing: 0
348
+ // The strip without an action: Back, an unavailable Up, the title, nothing else.
349
+ Flea.FlashStrip {
350
+ width: parent.width
351
+ onBack: root.close()
352
+ }
353
+ Flea.FlashImageRow {
354
+ width: parent.width
355
+ image: root.image
356
+ cursor: root.cursor === 0
357
+ focused: root.activeFocus
358
+ running: root.running
359
+ onChoose: {
360
+ root.cursor = 0
361
+ root.parkFocus()
362
+ root.contextPress()
363
+ }
364
+ }
365
+ Flea.FlashDriveRows {
366
+ width: parent.width
367
+ drives: root.drives
368
+ drivesReady: root.drivesReady
369
+ selected: root.selected
370
+ cursor: root.cursor
371
+ focused: root.activeFocus
372
+ running: root.running
373
+ onChooseDrive: function (index) {
374
+ root.chosen = root.drives[index]
375
+ root.cursor = root.flashRow
376
+ root.parkFocus()
377
+ }
378
+ }
379
+ // The Flash step: one 37 px row carrying the alert mark, the erase line and the action.
380
+ Flea.FlashStepRow {
381
+ id: stepRow
382
+ width: parent.width
383
+ transfer: root.transfer
384
+ rate: root.rate
385
+ words: root.words
386
+ live: root.live
387
+ running: root.running
388
+ ending: root.ending
389
+ ejected: root.ejected
390
+ cursor: root.cursor === root.flashRow
391
+ focused: root.activeFocus
392
+ onPressFlash: root.pressFlash()
393
+ onPressCancel: root.pressCancel()
394
+ onPressEnd: root.pressEnd()
395
+ }
396
+ }
397
+ }
@@ -0,0 +1,88 @@
1
+ import QtQuick
2
+ import QtQuick.Shapes
3
+ import "js/Motion.js" as Motion
4
+
5
+ // Flea's own mark: the Omarchy spiral redrawn as a 24-grid stroke glyph, per BrandMoments.dc.html's
6
+ // "The mark" cell. It paints itself in from blank and then holds. The caller drives the repeat, so
7
+ // the empty state's mark and its caption share one beat; the loading crawl (ui/Spinner.qml) stays a
8
+ // separate gesture on purpose, continuous where this one arrives and rests.
9
+ Item {
10
+ id: root
11
+
12
+ property color color: Theme.color.mutedFrame
13
+ // The mark draws on the same 24 unit grid as every Glyph, scaled to the slot.
14
+ readonly property real grid: 24
15
+ readonly property real markScale: Math.min(root.width, root.height) / root.grid
16
+ // The path below sums to this along its centreline: 18+18+18+14+14+10+10+6+6.
17
+ readonly property real markUnits: 114
18
+ // A brand mark, not a cut glyph: the spiral keeps the brand's 2 and is exempt from Theme.strokeWidth on purpose.
19
+ readonly property real brandStroke: 2
20
+ // QML dash units are strokeWidth multiples, so the whole mark is this many dashes long.
21
+ readonly property real markDashes: root.markUnits / root.brandStroke
22
+ readonly property bool settled: !draw.running && stroke.dashOffset === 0 && root.opacity === 1
23
+
24
+ // Repaints the mark from blank. EmptyState calls this off the caption's own timer so the two run
25
+ // on one beat; a second timer in here would drift against that one and read as sloppy.
26
+ function replay() {
27
+ if (Theme.reducedMotion) {
28
+ draw.stop()
29
+ stroke.dashOffset = 0
30
+ root.opacity = 1
31
+ } else draw.restart()
32
+ }
33
+
34
+ // A data-held folder lands whole, the settled frame the picture hold revealed.
35
+ function settle() { draw.stop(); stroke.dashOffset = 0; root.opacity = 1 }
36
+
37
+ Shape {
38
+ width: root.grid
39
+ height: root.grid
40
+ x: (root.width - root.grid * root.markScale) / 2
41
+ y: (root.height - root.grid * root.markScale) / 2
42
+ preferredRendererType: Shape.CurveRenderer
43
+ transform: Scale { xScale: root.markScale; yScale: root.markScale }
44
+
45
+ ShapePath {
46
+ id: stroke
47
+ strokeColor: root.color
48
+ fillColor: "transparent"
49
+ strokeWidth: root.brandStroke
50
+ capStyle: ShapePath.SquareCap
51
+ joinStyle: ShapePath.MiterJoin
52
+ strokeStyle: ShapePath.DashLine
53
+ // One dash and one gap, each the whole mark, so only ever one dash can sit on the path.
54
+ dashPattern: [root.markDashes, root.markDashes]
55
+ // A whole mark of offset draws nothing; the animation walks that back to zero.
56
+ dashOffset: root.markDashes
57
+ PathSvg { path: "M21 21H3V3h18v14H7V7h10v6h-6" }
58
+ }
59
+ }
60
+
61
+ // BrandMoments.dc.html's draw timing, 0.2s delay then 1.8s; OutCubic replaces its cubic-bezier(0.4, 0, 0.2, 1), the motion choice of 2026-09-25.
62
+ SequentialAnimation {
63
+ id: draw
64
+ // The caption's own fade-out, so a repeat dissolves the finished mark rather than cutting it.
65
+ NumberAnimation { target: root; property: "opacity"; to: 0.0; duration: Motion.durMs.close; easing.type: Easing.OutCubic }
66
+ // Blank before opacity comes back, never after: an offset of a whole mark is what hides the seam.
67
+ PropertyAction { target: stroke; property: "dashOffset"; value: root.markDashes }
68
+ PropertyAction { target: root; property: "opacity"; value: 1.0 }
69
+ PauseAnimation { duration: 200 }
70
+ NumberAnimation {
71
+ target: stroke
72
+ property: "dashOffset"
73
+ from: root.markDashes
74
+ to: 0
75
+ duration: 1800
76
+ easing.type: Easing.OutCubic
77
+ }
78
+ }
79
+
80
+ // The draw is the entrance as well as the loop, so it runs on every appearance; Item.visible reads effective visibility, so a hidden ancestor holds it back too.
81
+ onVisibleChanged: if (root.visible) root.replay(); else draw.stop()
82
+ // visible can already be true at creation, and onVisibleChanged never fires for that.
83
+ Component.onCompleted: if (root.visible) root.replay()
84
+ Connections {
85
+ target: Theme
86
+ function onReducedMotionChanged() { if (Theme.reducedMotion) root.replay() }
87
+ }
88
+ }