flea-qml 0.0.0-stage → 0.1.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 (625) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +478 -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 +402 -0
  51. package/src/archiveops.js +697 -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 +129 -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/transfer.js +669 -0
  82. package/src/trash-record.js +41 -0
  83. package/src/trash.js +210 -0
  84. package/src/trashbrowse.js +326 -0
  85. package/src/uistate.js +393 -0
  86. package/src/uistore.js +168 -0
  87. package/src/vendor/LICENSES/Apache-2.0.txt +202 -0
  88. package/src/vendor/LICENSES/MIT-katex-2015.txt +27 -0
  89. package/src/vendor/LICENSES/MIT-katex.txt +21 -0
  90. package/src/vendor/LICENSES/MIT-mermaid.txt +21 -0
  91. package/src/vendor/LICENSES/MIT-pele.txt +40 -0
  92. package/src/vendor/LICENSES/MIT-perseus.txt +18 -0
  93. package/src/vendor/LICENSES/MIT-temml.txt +21 -0
  94. package/src/vendor/pele.js +145 -0
  95. package/src/vendor/temml.mjs +14708 -0
  96. package/src/watch.js +98 -0
  97. package/src/wayland/client.js +109 -0
  98. package/src/wayland/protocol.js +55 -0
  99. package/src/wayland/protocols/ext-data-control-v1.xml +276 -0
  100. package/src/wayland/protocols/wayland.xml +3248 -0
  101. package/src/wayland/protocols/wlr-data-control-unstable-v1.xml +278 -0
  102. package/src/wayland/resource-io.js +6 -0
  103. package/src/wayland/socket-discovery.js +26 -0
  104. package/src/wayland/transport-posix.js +120 -0
  105. package/src/wayland/transport-win32.js +11 -0
  106. package/src/wayland/transport.js +3 -0
  107. package/src/wayland/win32-resources.js +80 -0
  108. package/src/wayland/win32-wire.js +62 -0
  109. package/test/archive.test.js +80 -0
  110. package/test/bench-markdown-scroll.mjs +190 -0
  111. package/test/clip-host.test.js +113 -0
  112. package/test/code-preview.test.js +35 -0
  113. package/test/compare-ui-paths.test.js +24 -0
  114. package/test/compare.test.js +54 -0
  115. package/test/delete-trash.test.js +67 -0
  116. package/test/dirsize.test.js +138 -0
  117. package/test/file-ops.test.js +241 -0
  118. package/test/find-contents.test.js +161 -0
  119. package/test/find-input.test.js +66 -0
  120. package/test/fixtures/pele-parity.json +1006 -0
  121. package/test/highlight-launcher.test.js +35 -0
  122. package/test/html-preview.test.js +22 -0
  123. package/test/input.test.js +15 -0
  124. package/test/keymap.test.js +26 -0
  125. package/test/language-icons.test.js +36 -0
  126. package/test/launcher.test.js +51 -0
  127. package/test/manual-code-scroll.mjs +28 -0
  128. package/test/manual-column-scroll.mjs +24 -0
  129. package/test/manual-compare-ui.mjs +20 -0
  130. package/test/manual-find-status.mjs +37 -0
  131. package/test/manual-html-security.mjs +23 -0
  132. package/test/manual-html-ui.mjs +30 -0
  133. package/test/manual-syntax-preview.mjs +26 -0
  134. package/test/manual-trash-ui.mjs +86 -0
  135. package/test/markdown-diagrams.test.js +93 -0
  136. package/test/markdown-html.test.js +105 -0
  137. package/test/mathml.test.js +92 -0
  138. package/test/menu-transfer.test.js +57 -0
  139. package/test/office-preview.test.js +154 -0
  140. package/test/pele-parity.test.js +28 -0
  141. package/test/places.test.js +134 -0
  142. package/test/preview-keys.test.js +60 -0
  143. package/test/preview-language.test.js +22 -0
  144. package/test/status-filename.test.js +20 -0
  145. package/test/transfer-replace-merge.test.js +187 -0
  146. package/test/trash-address.test.js +23 -0
  147. package/test/trash-view.test.js +37 -0
  148. package/test/trashbrowse.test.js +135 -0
  149. package/ui/AboutFacts.qml +78 -0
  150. package/ui/ArchiveCards.qml +68 -0
  151. package/ui/ArchiveCompressDialog.qml +378 -0
  152. package/ui/ArchivePasswordDialog.qml +257 -0
  153. package/ui/Backend.qml +771 -0
  154. package/ui/BulkOldNames.qml +47 -0
  155. package/ui/BulkRenameDialog.qml +380 -0
  156. package/ui/CardFrame.qml +67 -0
  157. package/ui/CardScroll.qml +79 -0
  158. package/ui/CheckBox.qml +73 -0
  159. package/ui/ChromeBar.qml +360 -0
  160. package/ui/ChromeButton.qml +131 -0
  161. package/ui/ChromeModes.qml +43 -0
  162. package/ui/CodeLines.qml +256 -0
  163. package/ui/CodeRefusal.qml +52 -0
  164. package/ui/CollideConfirm.qml +147 -0
  165. package/ui/CollideHost.qml +167 -0
  166. package/ui/ColumnPane.qml +523 -0
  167. package/ui/ColumnRow.qml +380 -0
  168. package/ui/ColumnsArea.qml +594 -0
  169. package/ui/ColumnsLanding.qml +147 -0
  170. package/ui/CompareView.qml +321 -0
  171. package/ui/ContextMenu.qml +743 -0
  172. package/ui/ConvertDialog.qml +456 -0
  173. package/ui/CountedWorker.qml +7 -0
  174. package/ui/Crumb.qml +64 -0
  175. package/ui/CrumbDrop.qml +25 -0
  176. package/ui/CsvTable.qml +394 -0
  177. package/ui/CursorMark.qml +41 -0
  178. package/ui/DefaultClaim.qml +130 -0
  179. package/ui/DeviceLock.qml +47 -0
  180. package/ui/DeviceMounts.qml +540 -0
  181. package/ui/DialogButton.qml +150 -0
  182. package/ui/DialogField.qml +147 -0
  183. package/ui/DialogHeader.qml +31 -0
  184. package/ui/DialogScrim.qml +20 -0
  185. package/ui/DialogTitle.qml +37 -0
  186. package/ui/Divider.qml +9 -0
  187. package/ui/DropInto.qml +126 -0
  188. package/ui/DropTarget.qml +35 -0
  189. package/ui/DropboxMark.qml +60 -0
  190. package/ui/EmptyState.qml +150 -0
  191. package/ui/EscapeHint.qml +11 -0
  192. package/ui/FactsTable.qml +54 -0
  193. package/ui/FastScrollHandler.qml +476 -0
  194. package/ui/FatNamesConfirm.qml +157 -0
  195. package/ui/Favourites.qml +143 -0
  196. package/ui/FigureService.qml +120 -0
  197. package/ui/FileDrag.qml +267 -0
  198. package/ui/FilterStrip.qml +133 -0
  199. package/ui/FitMetrics.qml +22 -0
  200. package/ui/FlashDriveRows.qml +137 -0
  201. package/ui/FlashHost.qml +72 -0
  202. package/ui/FlashImageRow.qml +104 -0
  203. package/ui/FlashRunner.qml +119 -0
  204. package/ui/FlashStepRow.qml +172 -0
  205. package/ui/FlashStrip.qml +38 -0
  206. package/ui/FlashView.qml +397 -0
  207. package/ui/FleaMark.qml +88 -0
  208. package/ui/FlyoutFade.qml +23 -0
  209. package/ui/FontPane.qml +170 -0
  210. package/ui/Glass.qml +114 -0
  211. package/ui/GlassTagger.qml +59 -0
  212. package/ui/Glyph.qml +64 -0
  213. package/ui/GlyphSolid.qml +22 -0
  214. package/ui/GridArea.qml +664 -0
  215. package/ui/GridTile.qml +325 -0
  216. package/ui/GvfsBridge.qml +164 -0
  217. package/ui/Header.qml +433 -0
  218. package/ui/HoverTimers.qml +39 -0
  219. package/ui/HtmlClip.qml +30 -0
  220. package/ui/HtmlPane.qml +63 -0
  221. package/ui/HyprlandMark.qml +45 -0
  222. package/ui/Ipc.qml +1005 -0
  223. package/ui/IpcControls.qml +7 -0
  224. package/ui/IpcMenuState.qml +48 -0
  225. package/ui/IpcPreviewState.qml +185 -0
  226. package/ui/JumpPath.qml +51 -0
  227. package/ui/KeymapSheet.qml +561 -0
  228. package/ui/KeymapSheetResult.qml +89 -0
  229. package/ui/KindStack.qml +40 -0
  230. package/ui/LangMark.qml +51 -0
  231. package/ui/LangMarkLoader.qml +26 -0
  232. package/ui/List.qml +480 -0
  233. package/ui/LoadingState.qml +54 -0
  234. package/ui/LocalSend.qml +56 -0
  235. package/ui/LocalSendMark.qml +73 -0
  236. package/ui/MarkdownBlockView.qml +311 -0
  237. package/ui/MarkdownBlocks.qml +35 -0
  238. package/ui/MarkdownFigure.qml +254 -0
  239. package/ui/MarkdownImages.qml +72 -0
  240. package/ui/MarkdownList.qml +81 -0
  241. package/ui/MarkdownMathsText.qml +97 -0
  242. package/ui/MarkdownPane.qml +83 -0
  243. package/ui/MarkdownPictures.qml +41 -0
  244. package/ui/MarkdownQuote.qml +52 -0
  245. package/ui/MarkdownRemote.qml +82 -0
  246. package/ui/MarkdownSource.qml +155 -0
  247. package/ui/MarkdownTable.qml +222 -0
  248. package/ui/MarkdownTableScroll.qml +64 -0
  249. package/ui/MarkdownTableWheel.qml +126 -0
  250. package/ui/MarkdownText.qml +87 -0
  251. package/ui/MarkdownWorker.js +132 -0
  252. package/ui/MatchText.qml +99 -0
  253. package/ui/MediaSession.qml +38 -0
  254. package/ui/MediaSound.qml +26 -0
  255. package/ui/MediaStrip.qml +191 -0
  256. package/ui/MediaTrack.qml +36 -0
  257. package/ui/MediaVolume.qml +54 -0
  258. package/ui/MenuActionDialog.qml +396 -0
  259. package/ui/MenuEdgeFade.qml +24 -0
  260. package/ui/MenuHost.qml +227 -0
  261. package/ui/MenuRow.qml +351 -0
  262. package/ui/MountListing.qml +100 -0
  263. package/ui/NetworkDialog.qml +435 -0
  264. package/ui/NetworkForm.qml +426 -0
  265. package/ui/NetworkMounts.qml +913 -0
  266. package/ui/NetworkPlaces.qml +127 -0
  267. package/ui/OpenWithDialog.qml +613 -0
  268. package/ui/Opener.qml +115 -0
  269. package/ui/Pane.qml +1296 -0
  270. package/ui/PaneMenuActions.qml +527 -0
  271. package/ui/PanePath.qml +90 -0
  272. package/ui/PaneRail.qml +239 -0
  273. package/ui/PaneStates.qml +88 -0
  274. package/ui/PaneSwap.qml +339 -0
  275. package/ui/PaneWire.qml +605 -0
  276. package/ui/ParkedWait.qml +9 -0
  277. package/ui/PathEntry.qml +186 -0
  278. package/ui/PathJump.qml +400 -0
  279. package/ui/PdfViewer.qml +297 -0
  280. package/ui/PermissionsDialog.qml +658 -0
  281. package/ui/PermissionsHeadings.qml +31 -0
  282. package/ui/PhoneMounts.qml +67 -0
  283. package/ui/PickerAnswers.qml +75 -0
  284. package/ui/PickerBox.qml +26 -0
  285. package/ui/PickerChrome.qml +295 -0
  286. package/ui/PickerFilter.qml +97 -0
  287. package/ui/PickerGrid.qml +308 -0
  288. package/ui/PickerHeader.qml +28 -0
  289. package/ui/PickerLifecycle.qml +27 -0
  290. package/ui/PickerList.qml +218 -0
  291. package/ui/PickerListing.qml +149 -0
  292. package/ui/PickerPathBar.qml +127 -0
  293. package/ui/PickerPlaces.qml +189 -0
  294. package/ui/PickerRecent.qml +92 -0
  295. package/ui/PickerSave.qml +101 -0
  296. package/ui/PickerSelection.qml +155 -0
  297. package/ui/PickerWindow.qml +846 -0
  298. package/ui/PowerSectorsReader.qml +10 -0
  299. package/ui/PrebuildDriver.qml +146 -0
  300. package/ui/Preview.qml +1004 -0
  301. package/ui/PreviewAnimation.qml +24 -0
  302. package/ui/PreviewArchive.qml +66 -0
  303. package/ui/PreviewColumn.qml +551 -0
  304. package/ui/PreviewEdge.qml +63 -0
  305. package/ui/PreviewFacts.qml +30 -0
  306. package/ui/PreviewFactsLine.qml +34 -0
  307. package/ui/PreviewHtml.qml +233 -0
  308. package/ui/PreviewImage.qml +253 -0
  309. package/ui/PreviewImagePan.qml +13 -0
  310. package/ui/PreviewImageSharp.qml +32 -0
  311. package/ui/PreviewLines.qml +106 -0
  312. package/ui/PreviewMarkdown.qml +706 -0
  313. package/ui/PreviewMedia.qml +250 -0
  314. package/ui/PreviewPdf.qml +482 -0
  315. package/ui/PreviewScroll.qml +201 -0
  316. package/ui/PreviewSwap.qml +335 -0
  317. package/ui/PreviewText.qml +149 -0
  318. package/ui/ProtocolChip.qml +18 -0
  319. package/ui/QuickLookArchive.qml +38 -0
  320. package/ui/QuickLookBar.qml +103 -0
  321. package/ui/QuickLookPrepare.qml +355 -0
  322. package/ui/QuickLookSwap.qml +10 -0
  323. package/ui/QuickLookWarm.qml +65 -0
  324. package/ui/RailDrop.qml +155 -0
  325. package/ui/RailHeading.qml +19 -0
  326. package/ui/RailPlaces.qml +38 -0
  327. package/ui/RailTrashRow.qml +67 -0
  328. package/ui/RenameField.qml +353 -0
  329. package/ui/RendererRetry.qml +11 -0
  330. package/ui/ResizeHandle.qml +52 -0
  331. package/ui/Reveal.qml +54 -0
  332. package/ui/Row.qml +476 -0
  333. package/ui/RowDrag.qml +213 -0
  334. package/ui/RowDropTarget.qml +27 -0
  335. package/ui/RunCard.qml +286 -0
  336. package/ui/Scripts.qml +65 -0
  337. package/ui/SearchStrip.qml +232 -0
  338. package/ui/SelectionBand.qml +140 -0
  339. package/ui/SelectionPreview.qml +370 -0
  340. package/ui/SettingsFavourite.qml +122 -0
  341. package/ui/SettingsGroup.qml +96 -0
  342. package/ui/SettingsHint.qml +12 -0
  343. package/ui/SettingsMetrics.qml +29 -0
  344. package/ui/SettingsPane.qml +178 -0
  345. package/ui/SettingsPanel.qml +547 -0
  346. package/ui/SettingsRail.qml +128 -0
  347. package/ui/SettingsRow.qml +409 -0
  348. package/ui/SettingsRuler.qml +85 -0
  349. package/ui/SettingsSegment.qml +85 -0
  350. package/ui/ShareBrowser.qml +113 -0
  351. package/ui/ShareLink.qml +67 -0
  352. package/ui/ShelfPins.qml +101 -0
  353. package/ui/Sidebar.qml +732 -0
  354. package/ui/SidebarRow.qml +358 -0
  355. package/ui/Spinner.qml +60 -0
  356. package/ui/StableModel.qml +89 -0
  357. package/ui/StateMessage.qml +84 -0
  358. package/ui/StatusBar.qml +512 -0
  359. package/ui/StatusFileName.qml +27 -0
  360. package/ui/TabBar.qml +673 -0
  361. package/ui/TabDragGeometry.qml +60 -0
  362. package/ui/TagMenuMark.qml +52 -0
  363. package/ui/TagRailSection.qml +53 -0
  364. package/ui/TagSlot.qml +40 -0
  365. package/ui/TagState.qml +150 -0
  366. package/ui/TagSwatch.qml +28 -0
  367. package/ui/Taildrop.qml +86 -0
  368. package/ui/TailscaleMark.qml +50 -0
  369. package/ui/Theme.qml +460 -0
  370. package/ui/ThemeColors.qml +43 -0
  371. package/ui/TransferCard.qml +239 -0
  372. package/ui/TrashConfirm.qml +129 -0
  373. package/ui/TrashDropHandler.qml +11 -0
  374. package/ui/TrashHost.qml +202 -0
  375. package/ui/TrashMonitor.qml +30 -0
  376. package/ui/TrashToolbar.qml +19 -0
  377. package/ui/TrashView.qml +492 -0
  378. package/ui/UnlockDialog.qml +450 -0
  379. package/ui/UnlockHost.qml +206 -0
  380. package/ui/UpdateCheck.qml +97 -0
  381. package/ui/UserDirs.qml +25 -0
  382. package/ui/ViewState.qml +565 -0
  383. package/ui/ViewportScrollBar.qml +195 -0
  384. package/ui/ViewportScrollBars.qml +25 -0
  385. package/ui/WebPreview.qml +33 -0
  386. package/ui/WebPreviewView.qml +26 -0
  387. package/ui/WindowBody.qml +827 -0
  388. package/ui/WindowDrag.qml +35 -0
  389. package/ui/boot/Commons/AudioNodes.qml +50 -0
  390. package/ui/boot/Commons/AudioNodesModel.js +96 -0
  391. package/ui/boot/Commons/Border.qml +243 -0
  392. package/ui/boot/Commons/BorderGeometry.js +373 -0
  393. package/ui/boot/Commons/Color.qml +258 -0
  394. package/ui/boot/Commons/I18n.qml +118 -0
  395. package/ui/boot/Commons/InputDevices.qml +112 -0
  396. package/ui/boot/Commons/InputMethodState.qml +38 -0
  397. package/ui/boot/Commons/IpcRegistry.qml +77 -0
  398. package/ui/boot/Commons/Numbers.js +19 -0
  399. package/ui/boot/Commons/Plural.js +91 -0
  400. package/ui/boot/Commons/ShellIpc.qml +12 -0
  401. package/ui/boot/Commons/Style.qml +561 -0
  402. package/ui/boot/Commons/Translations.qml +100 -0
  403. package/ui/boot/Commons/UntypedInput.qml +152 -0
  404. package/ui/boot/Commons/Util.qml +188 -0
  405. package/ui/boot/Commons/qmldir +13 -0
  406. package/ui/boot/LICENSE-omarchy +20 -0
  407. package/ui/boot/Ui/BackgroundMedia.qml +49 -0
  408. package/ui/boot/Ui/BarIconButton.qml +106 -0
  409. package/ui/boot/Ui/BarIconContent.qml +38 -0
  410. package/ui/boot/Ui/BarIndicator.qml +53 -0
  411. package/ui/boot/Ui/BarWidget.qml +50 -0
  412. package/ui/boot/Ui/BorderOverlay.qml +54 -0
  413. package/ui/boot/Ui/BorderSurface.qml +40 -0
  414. package/ui/boot/Ui/Button.qml +224 -0
  415. package/ui/boot/Ui/ButtonGroup.qml +131 -0
  416. package/ui/boot/Ui/ConfirmDialog.qml +134 -0
  417. package/ui/boot/Ui/CursorSurface.qml +42 -0
  418. package/ui/boot/Ui/Dropdown.qml +245 -0
  419. package/ui/boot/Ui/FilterInput.qml +26 -0
  420. package/ui/boot/Ui/IconContentBounds.qml +141 -0
  421. package/ui/boot/Ui/KeyboardPanel.qml +453 -0
  422. package/ui/boot/Ui/MultiSelect.qml +624 -0
  423. package/ui/boot/Ui/NumberField.qml +86 -0
  424. package/ui/boot/Ui/OpticalGlyph.qml +68 -0
  425. package/ui/boot/Ui/OverlayWindow.qml +102 -0
  426. package/ui/boot/Ui/Panel.qml +60 -0
  427. package/ui/boot/Ui/PanelActionButton.qml +105 -0
  428. package/ui/boot/Ui/PanelController.qml +16 -0
  429. package/ui/boot/Ui/PanelHero.qml +112 -0
  430. package/ui/boot/Ui/PanelKeyCatcher.qml +100 -0
  431. package/ui/boot/Ui/PanelSectionHeader.qml +31 -0
  432. package/ui/boot/Ui/PanelSeparator.qml +19 -0
  433. package/ui/boot/Ui/PanelSlider.qml +156 -0
  434. package/ui/boot/Ui/PanelToolTip.qml +50 -0
  435. package/ui/boot/Ui/PluginBarApi.qml +89 -0
  436. package/ui/boot/Ui/PointerMoveGate.qml +54 -0
  437. package/ui/boot/Ui/PopupCard.qml +181 -0
  438. package/ui/boot/Ui/ScreenMoveRemap.qml +43 -0
  439. package/ui/boot/Ui/SearchableDropdown.qml +354 -0
  440. package/ui/boot/Ui/SizedImage.qml +125 -0
  441. package/ui/boot/Ui/SpeedTestOverlay.qml +412 -0
  442. package/ui/boot/Ui/TextField.qml +58 -0
  443. package/ui/boot/Ui/Toggle.qml +118 -0
  444. package/ui/boot/Ui/ToggleSwitch.qml +115 -0
  445. package/ui/boot/Ui/WidgetButton.qml +172 -0
  446. package/ui/boot/Ui/qmldir +41 -0
  447. package/ui/boot/fleatab.qml +50 -0
  448. package/ui/boot/picker.qml +39 -0
  449. package/ui/boot/shell.qml +122 -0
  450. package/ui/boot/tabtearoff.qml +51 -0
  451. package/ui/js/Anchor.js +379 -0
  452. package/ui/js/AnchorHold.js +162 -0
  453. package/ui/js/Archive.js +157 -0
  454. package/ui/js/ArchiveCard.js +44 -0
  455. package/ui/js/ArchiveOps.js +44 -0
  456. package/ui/js/BackReturn.js +118 -0
  457. package/ui/js/BulkRename.js +100 -0
  458. package/ui/js/Buttons.js +54 -0
  459. package/ui/js/ChromeKeys.js +116 -0
  460. package/ui/js/ClipMarks.js +73 -0
  461. package/ui/js/ClipSelection.js +67 -0
  462. package/ui/js/Clipboard.js +179 -0
  463. package/ui/js/Cloud.js +97 -0
  464. package/ui/js/CodeRuns.js +72 -0
  465. package/ui/js/Collide.js +212 -0
  466. package/ui/js/ColumnFit.js +28 -0
  467. package/ui/js/ColumnMenu.js +111 -0
  468. package/ui/js/Columns.js +298 -0
  469. package/ui/js/ColumnsCarry.js +103 -0
  470. package/ui/js/Compare.js +74 -0
  471. package/ui/js/Contrast.js +157 -0
  472. package/ui/js/ControlReader.js +42 -0
  473. package/ui/js/Convert.js +52 -0
  474. package/ui/js/CopyAs.js +52 -0
  475. package/ui/js/Crumbs.js +178 -0
  476. package/ui/js/Csv.js +231 -0
  477. package/ui/js/Density.js +44 -0
  478. package/ui/js/Devices.js +440 -0
  479. package/ui/js/DirSizes.js +180 -0
  480. package/ui/js/Drag.js +364 -0
  481. package/ui/js/DragOut.js +166 -0
  482. package/ui/js/DropDev.js +52 -0
  483. package/ui/js/Dropbox.js +41 -0
  484. package/ui/js/Eject.js +217 -0
  485. package/ui/js/Errors.js +188 -0
  486. package/ui/js/ExtThumbs.js +115 -0
  487. package/ui/js/Facts.js +402 -0
  488. package/ui/js/FigureDate.js +14 -0
  489. package/ui/js/Filter.js +285 -0
  490. package/ui/js/Find.js +46 -0
  491. package/ui/js/Flash.js +184 -0
  492. package/ui/js/FlashCard.js +79 -0
  493. package/ui/js/FlashEndings.js +125 -0
  494. package/ui/js/FlashPane.js +116 -0
  495. package/ui/js/FleaBin.js +12 -0
  496. package/ui/js/Focus.js +502 -0
  497. package/ui/js/FolderSorts.js +108 -0
  498. package/ui/js/FolderViews.js +44 -0
  499. package/ui/js/Format.js +305 -0
  500. package/ui/js/Fuzzy.js +141 -0
  501. package/ui/js/GlassTag.js +72 -0
  502. package/ui/js/Grid.js +33 -0
  503. package/ui/js/GridGeometry.js +90 -0
  504. package/ui/js/GridNames.js +153 -0
  505. package/ui/js/GvfsBridge.js +200 -0
  506. package/ui/js/HostClipboard.js +29 -0
  507. package/ui/js/Icons.js +218 -0
  508. package/ui/js/Input.js +50 -0
  509. package/ui/js/Jump.js +200 -0
  510. package/ui/js/KeyName.js +64 -0
  511. package/ui/js/Keymap.js +401 -0
  512. package/ui/js/Kinds.js +164 -0
  513. package/ui/js/LICENSES/ISC-lucide.txt +43 -0
  514. package/ui/js/LangMarkPaths.js +47 -0
  515. package/ui/js/LangMarks.js +120 -0
  516. package/ui/js/Lists.js +11 -0
  517. package/ui/js/LocalSend.js +39 -0
  518. package/ui/js/LockedMenu.js +63 -0
  519. package/ui/js/MakeDefault.js +186 -0
  520. package/ui/js/MarkBox.js +7 -0
  521. package/ui/js/Markdown.js +119 -0
  522. package/ui/js/MarkdownLists.js +86 -0
  523. package/ui/js/MarkdownMaths.js +58 -0
  524. package/ui/js/MarkdownPictures.js +32 -0
  525. package/ui/js/MarkdownPrepared.js +139 -0
  526. package/ui/js/MarkdownTableFit.js +34 -0
  527. package/ui/js/Marks.js +148 -0
  528. package/ui/js/Marquee.js +96 -0
  529. package/ui/js/Match.js +93 -0
  530. package/ui/js/Material.js +109 -0
  531. package/ui/js/MdBlocks.js +437 -0
  532. package/ui/js/MdBreak.js +71 -0
  533. package/ui/js/MdChunks.js +70 -0
  534. package/ui/js/MdContainer.js +137 -0
  535. package/ui/js/MdDocument.js +337 -0
  536. package/ui/js/MdEmph.js +97 -0
  537. package/ui/js/MdEntity.js +108 -0
  538. package/ui/js/MdEntityTable.js +223 -0
  539. package/ui/js/MdEscape.js +59 -0
  540. package/ui/js/MdFront.js +37 -0
  541. package/ui/js/MdHold.js +32 -0
  542. package/ui/js/MdHtml.js +307 -0
  543. package/ui/js/MdHtmlBlock.js +290 -0
  544. package/ui/js/MdHtmlHeading.js +53 -0
  545. package/ui/js/MdHtmlImage.js +179 -0
  546. package/ui/js/MdInline.js +154 -0
  547. package/ui/js/MdItems.js +212 -0
  548. package/ui/js/MdLeaf.js +309 -0
  549. package/ui/js/MdLink.js +196 -0
  550. package/ui/js/MdMath.js +67 -0
  551. package/ui/js/MdParagraphs.js +138 -0
  552. package/ui/js/MdRefs.js +232 -0
  553. package/ui/js/MdResolve.js +226 -0
  554. package/ui/js/MdRun.js +300 -0
  555. package/ui/js/MdUrl.js +226 -0
  556. package/ui/js/Menu.js +514 -0
  557. package/ui/js/MenuContext.js +85 -0
  558. package/ui/js/MenuFit.js +13 -0
  559. package/ui/js/MenuRefresh.js +74 -0
  560. package/ui/js/MenuWheel.js +35 -0
  561. package/ui/js/Messages.js +186 -0
  562. package/ui/js/Motion.js +16 -0
  563. package/ui/js/Mounts.js +320 -0
  564. package/ui/js/MouseNav.js +13 -0
  565. package/ui/js/Nav.js +329 -0
  566. package/ui/js/NetFs.js +26 -0
  567. package/ui/js/OpenWith.js +83 -0
  568. package/ui/js/Ops.js +585 -0
  569. package/ui/js/Palette.js +33 -0
  570. package/ui/js/PathBar.js +260 -0
  571. package/ui/js/Permissions.js +179 -0
  572. package/ui/js/Phones.js +112 -0
  573. package/ui/js/Picker.js +353 -0
  574. package/ui/js/PlaceMenu.js +96 -0
  575. package/ui/js/Places.js +265 -0
  576. package/ui/js/PreviewAsk.js +21 -0
  577. package/ui/js/PreviewKeys.js +155 -0
  578. package/ui/js/PreviewSettle.js +29 -0
  579. package/ui/js/PreviewSwap.js +101 -0
  580. package/ui/js/PropertyFacts.js +144 -0
  581. package/ui/js/Protocols.js +296 -0
  582. package/ui/js/QuickLookKinds.js +27 -0
  583. package/ui/js/QuickLookRect.js +24 -0
  584. package/ui/js/RailDrop.js +51 -0
  585. package/ui/js/RailKeys.js +87 -0
  586. package/ui/js/RailMenu.js +133 -0
  587. package/ui/js/Recent.js +135 -0
  588. package/ui/js/RecentMode.js +156 -0
  589. package/ui/js/Reload.js +60 -0
  590. package/ui/js/Renderer.js +9 -0
  591. package/ui/js/RunFile.js +143 -0
  592. package/ui/js/Scripts.js +28 -0
  593. package/ui/js/Scroll.js +304 -0
  594. package/ui/js/ScrollOff.js +69 -0
  595. package/ui/js/Search.js +478 -0
  596. package/ui/js/Selection.js +97 -0
  597. package/ui/js/Settings.js +476 -0
  598. package/ui/js/SettingsAbout.js +97 -0
  599. package/ui/js/SettingsShelf.js +52 -0
  600. package/ui/js/SheetKeys.js +42 -0
  601. package/ui/js/SheetQuery.js +281 -0
  602. package/ui/js/ShelfPile.js +27 -0
  603. package/ui/js/SlowClick.js +53 -0
  604. package/ui/js/SlowOp.js +6 -0
  605. package/ui/js/Sort.js +134 -0
  606. package/ui/js/Startup.js +63 -0
  607. package/ui/js/StateWords.js +17 -0
  608. package/ui/js/Status.js +238 -0
  609. package/ui/js/Swap.js +166 -0
  610. package/ui/js/TabMove.js +39 -0
  611. package/ui/js/Tabs.js +736 -0
  612. package/ui/js/Tags.js +134 -0
  613. package/ui/js/Taildrop.js +128 -0
  614. package/ui/js/Tap.js +174 -0
  615. package/ui/js/TextSize.js +107 -0
  616. package/ui/js/Thumbs.js +158 -0
  617. package/ui/js/Transfer.js +172 -0
  618. package/ui/js/Trash.js +81 -0
  619. package/ui/js/TrashDates.js +47 -0
  620. package/ui/js/TrashDrop.js +64 -0
  621. package/ui/js/UiState.js +438 -0
  622. package/ui/js/Unlock.js +152 -0
  623. package/ui/js/Update.js +130 -0
  624. package/ui/js/UserDirs.js +56 -0
  625. package/ui/qmldir +228 -0
@@ -0,0 +1,40 @@
1
+ import QtQuick
2
+ import "." as Flea
3
+
4
+ // The marks a multi-selection stacks in the preview frame, one per kind, front-most first. The
5
+ // canvas offsets its marks a quarter of the mark across and an eleventh of it down, so both steps
6
+ // are measured against the mark this pane actually draws, HANDOFF rule 17's stateMarkSize.
7
+ Item {
8
+ id: root
9
+
10
+ // Glyph names, front-most first, as ui/js/Facts.js multiMarks builds them.
11
+ property var marks: []
12
+
13
+ readonly property int stepX: Math.round(Theme.stateMarkSize / 4)
14
+ readonly property int stepY: Math.round(Theme.stateMarkSize / 11)
15
+ // Every mark behind the front one is a step fainter, which is the canvas's 1.0, 0.7 and 0.4.
16
+ readonly property real fade: 0.3
17
+ readonly property int steps: Math.max(0, root.marks.length - 1)
18
+
19
+ width: Theme.stateMarkSize + root.steps * root.stepX
20
+ height: Theme.stateMarkSize + root.steps * root.stepY
21
+
22
+ Repeater {
23
+ model: root.marks
24
+
25
+ delegate: Flea.Glyph {
26
+ required property string modelData
27
+ required property int index
28
+ // Model order paints back to front, so the front mark has to claim its own z.
29
+ z: root.marks.length - index
30
+ x: (root.steps - index) * root.stepX
31
+ y: index * root.stepY
32
+ maxSize: Theme.stateMarkSize
33
+ width: Theme.stateMarkSize
34
+ height: Theme.stateMarkSize
35
+ name: modelData
36
+ color: Theme.color.mutedFrame
37
+ opacity: 1 - index * root.fade
38
+ }
39
+ }
40
+ }
@@ -0,0 +1,51 @@
1
+ import QtQuick
2
+ import QtQuick.Shapes
3
+ import "js/LangMarkPaths.js" as LangMarkPaths
4
+
5
+ // A language logo on the file page: stroked page plus filled logo in the same ink.
6
+ Item {
7
+ id: root
8
+
9
+ property string slug: ""
10
+ property color color: "transparent"
11
+ // Shared 24-unit grid with ui/js/Icons.js.
12
+ readonly property real grid: 24
13
+ // Caller ceiling; without one it draws nothing (fails loud).
14
+ property real maxSize
15
+ // "scale" would shadow Item.scale, as in ui/Glyph.qml.
16
+ readonly property real markSize: Math.min(root.maxSize, root.width, root.height)
17
+ readonly property real gridScale: root.markSize / root.grid
18
+ // Board's two-unit stroke on the shared grid.
19
+ property real strokeWidth: 2
20
+ // Caller caps; false is the Omarchy cut.
21
+ property bool roundCaps: false
22
+
23
+ // File page with the corner cut for the logo box (x 1..15, y 9..23).
24
+ readonly property string page: "M4 7V2h10l6 6v14H17 M14 2v6h6"
25
+
26
+ // Grid-sized Shape re-centered in the slot (Scale origin is 0,0).
27
+ Shape {
28
+ width: root.grid
29
+ height: root.grid
30
+ x: (root.width - root.markSize) / 2
31
+ y: (root.height - root.markSize) / 2
32
+ preferredRendererType: Shape.CurveRenderer
33
+ transform: Scale { xScale: root.gridScale; yScale: root.gridScale }
34
+
35
+ ShapePath {
36
+ strokeColor: root.color
37
+ fillColor: "transparent"
38
+ strokeWidth: root.strokeWidth
39
+ capStyle: root.roundCaps ? ShapePath.RoundCap : ShapePath.SquareCap
40
+ joinStyle: root.roundCaps ? ShapePath.RoundJoin : ShapePath.MiterJoin
41
+ PathSvg { path: root.page }
42
+ }
43
+
44
+ // Filled logo baked via translate(1 9) scale(14/24); see ui/js/LangMarkPaths.js.
45
+ ShapePath {
46
+ strokeColor: "transparent"
47
+ fillColor: root.color
48
+ PathSvg { path: LangMarkPaths.pathFor(root.slug) }
49
+ }
50
+ }
51
+ }
@@ -0,0 +1,26 @@
1
+ pragma ComponentBehavior: Bound
2
+ import QtQuick
3
+ import qs.Commons
4
+
5
+ // Only a row with a visible language logo builds it; the glyph supplies its geometry.
6
+ Loader {
7
+ id: root
8
+
9
+ required property Item owner
10
+ required property Item glyph
11
+ active: !root.owner.thumbDrawn && root.owner.langSlug !== ""
12
+ visible: !root.owner.thumbDrawn && root.owner.langSlug !== ""
13
+ x: root.glyph.x
14
+ y: root.glyph.y
15
+ width: root.glyph.width
16
+ height: root.glyph.height
17
+ sourceComponent: LangMark {
18
+ anchors.fill: parent
19
+ maxSize: root.glyph.maxSize
20
+ slug: root.owner.langSlug
21
+ color: root.glyph.color
22
+ strokeWidth: root.glyph.strokeWidth
23
+ roundCaps: ViewState.hyprlandIcons && Style.cornerRadius > 0
24
+ }
25
+ onStatusChanged: if (status === Loader.Error) throw new Error("LangMark.qml did not load: Loader status " + status)
26
+ }
package/ui/List.qml ADDED
@@ -0,0 +1,480 @@
1
+ import QtQuick
2
+ import "." as Flea
3
+ import "js/ClipMarks.js" as ClipMarks
4
+ import "js/DirSizes.js" as DirSizes
5
+ import "js/ExtThumbs.js" as ExtThumbs
6
+ import "js/Filter.js" as Filter
7
+ import "js/Scroll.js" as Scroll
8
+ import "js/ScrollOff.js" as ScrollOff
9
+ import "js/Tap.js" as Tap
10
+ import "js/Thumbs.js" as Thumbs
11
+
12
+ // The listing's render, scroll and settle-triggered refetch, split out of Pane.qml; reaches Pane's state through the pane reference and the context menu through menu, both handed in at instantiation.
13
+ ListView {
14
+ id: root
15
+
16
+ property var pane: null
17
+ readonly property bool fileDragActive: dragSession.Drag.active
18
+ property var menu: null
19
+
20
+ // Parked rows built ahead of the next landing; a row parks invisible and the landing shows it again.
21
+ readonly property Flea.PrebuildDriver prebuild: Flea.PrebuildDriver {
22
+ view: root
23
+ model: stable
24
+ pane: root.pane
25
+ limit: stable.warmRows
26
+ held: root.hiddenHeld
27
+ park: function (cell) { cell.live = false; cell.visible = false }
28
+ adopt: function (cell) { cell.live = true; cell.visible = true; cursorMark.place(cell) }
29
+ }
30
+
31
+ // Shared once, read plainly per row, so no delegate builds its own width or array.
32
+ property real rowWidth: Scroll.contentWidth(root.width, Theme.spacing.rowPaddingX)
33
+ // Dual mode hides mode and kind on top of the stored set; one array, never one per row.
34
+ property var rowHiddenCols: root.pane && root.pane.dualMode ? ["mode", "kind"].concat(ViewState.hiddenCols) : ViewState.hiddenCols
35
+ // Shared name budgets remove the per-row floor; Row keeps its local default for PickerList and drop targets.
36
+ readonly property bool listDual: root.pane && root.pane.dualMode ? true : false
37
+ readonly property real listMarkSlot: root.listDual ? Theme.markSize : Theme.iconSize
38
+ readonly property real listSizeWidth: root.listDual ? Theme.dualColumn.size : Theme.column.size
39
+ readonly property real listDateWidth: root.listDual ? Theme.dualColumn.date : Theme.column.date
40
+ // The same set Row.cols resolves, from the same width and hidden array, so the two cannot drift.
41
+ readonly property var listCols: root.pane && root.pane.recentMode.length > 0 ? Theme.columns(root.rowWidth, root.rowHiddenCols, root.listDateWidth, true, root.listDual) : root.listDual ? Theme.dualColumns(root.rowWidth, root.rowHiddenCols) : Theme.columns(root.rowWidth, root.rowHiddenCols, root.listDateWidth)
42
+ readonly property bool listModeShown: root.listCols ? !!root.listCols.mode : false
43
+ readonly property bool listSizeShown: root.listCols ? !!root.listCols.size : false
44
+ readonly property bool listDateShown: root.listCols ? !!root.listCols.date : false
45
+ readonly property bool listKindShown: root.listCols ? !!root.listCols.kind : false
46
+ // Matches Theme.clipMarkSize; the reserve keeps the glyph readable.
47
+ readonly property int listClipPx: Theme.clipMarkSize
48
+ // Exact drawn geometry: the row less padding, mark, gap, columns, gaps and name-to-mode gap, in pixels then floored.
49
+ readonly property real nameSlotPlainPx: Math.max(0, root.rowWidth - 2 * Theme.spacing.rowPaddingX - root.listMarkSlot - Theme.spacing.gap - (root.listModeShown ? Theme.column.mode : 0) - (root.listSizeShown ? root.listSizeWidth : 0) - (root.listDateShown ? root.listDateWidth : 0) - (root.listKindShown ? Theme.column.kind : 0) - (root.listKindShown ? Theme.spacing.gap : 0) - ((root.listDateShown && !root.listDual) ? Theme.spacing.gap : 0) - ((root.listSizeShown && !root.listDual) ? Theme.spacing.gap : 0) - (root.listModeShown ? Theme.spacing.gap : 0))
50
+ readonly property real nameSlotClipPx: Math.max(0, root.nameSlotPlainPx - Theme.spacing.gap - root.listClipPx)
51
+ readonly property int nameBudgetPlain: Theme.bodyAdvance > 0 && root.nameSlotPlainPx > 0 ? Math.floor(root.nameSlotPlainPx / Theme.bodyAdvance) : -1
52
+ readonly property int nameBudgetClip: Theme.bodyAdvance > 0 && root.nameSlotClipPx > 0 ? Math.floor(root.nameSlotClipPx / Theme.bodyAdvance) : -1
53
+ property bool clipEmpty: ClipMarks.isEmpty(root.pane ? root.pane.clipboard : null)
54
+ // The short-circuit below is the only release while empty, so a cut of a large directory frees its lookup here.
55
+ onClipEmptyChanged: { if (root.clipEmpty) ClipMarks.release() }
56
+
57
+ // Pane owns cursorIndex, thumbState and dirSizeState; List only computes what changed and hands it back.
58
+ // Both ends of cursorClamped are view positions, not listing rows: under a filter they differ.
59
+ signal cursorClamped(int first, int last)
60
+ signal thumbsApplied(var work)
61
+ signal dirSizesApplied(var ask)
62
+ signal dirSizesCancelled()
63
+
64
+ focus: true
65
+ keyNavigationEnabled: false
66
+ // Hidden holds no delegates; an edit the List held when it hid keeps its own per RenameField.qml.
67
+ model: Flea.StableModel { id: stable; view: root; total: (root.visible || root.renameHeld) ? root.pane.shownTotal : 0
68
+ warm: root.visible && root.pane.searchMode.length > 0 && root.pane.swap.searchWarm === true; warmRows: Math.floor((root.height + root.cacheBuffer) / Theme.fileRowHeight) + 1 }
69
+ clip: true
70
+ cacheBuffer: Theme.fileRowHeight * pane.cacheRows
71
+ boundsBehavior: Flickable.StopAtBounds
72
+ highlightMoveDuration: 0
73
+ // Every property the delegate draws binds to index and cursor is refiled by listingIndex, so a row leaving the buffer is re-bound rather than rebuilt.
74
+ reuseItems: true
75
+ // The one row drawn as the cursor; a cursor move touches two delegates, not every live one.
76
+ Flea.CursorMark { id: cursorMark; row: root.pane.cursorIndex }
77
+
78
+ Flea.FastScrollHandler {
79
+ parent: root
80
+ flickable: root
81
+ }
82
+
83
+ readonly property alias scrollBar: verticalScroll
84
+ Flea.ViewportScrollBar {
85
+ id: verticalScroll
86
+ parent: root
87
+ anchors { top: parent.top; right: parent.right }
88
+ flickable: root
89
+ }
90
+
91
+ Flea.SelectionBand {
92
+ parent: root
93
+ pane: root.pane
94
+ flickable: root
95
+ }
96
+
97
+ Flea.FileDrag {
98
+ id: dragSession
99
+ pane: root.pane
100
+ }
101
+
102
+ delegate: Flea.Row {
103
+ id: cell
104
+ required property int index
105
+ // Parked while pooled: each listing read returns its own last value until onReused rebinds it before the next frame; a row holding the open editor stays live, since a prebuild create pools and reuses the shown rows and pooling would destroy the editor.
106
+ property bool live: true
107
+ ListView.onPooled: if (!cell.renaming) cell.live = false
108
+ ListView.onReused: {
109
+ // The driver's create can take a pooled row past the shown ones; it parks as a built one does.
110
+ if (cell.index >= root.count) { root.prebuild.parkCell(cell); return }
111
+ cell.live = true
112
+ root.prebuild.adoptCell(cell)
113
+ }
114
+ // Built ahead of a landing past the shown rows: parked invisible until the landing reuses it.
115
+ property bool prebuilt: false
116
+ Component.onDestruction: root.prebuild.gone(cell)
117
+ // index is where the row is drawn; listingIndex is the row the backend numbers, and under a
118
+ // filter the two are different. Everything that leaves this delegate takes the listing one.
119
+ readonly property int listingIndex: cell.live ? Filter.at(root.pane.shown, index) : -1
120
+ // Filed by listing row in the view's cursor mark, which sets cursor; see ui/CursorMark.qml.
121
+ property int markRow: -1
122
+ Component.onCompleted: if (!root.prebuild.built(cell)) cursorMark.place(cell)
123
+ onListingIndexChanged: cursorMark.place(cell)
124
+ // The scroll lane stays clear so rows never reflow under the bar.
125
+ width: root.rowWidth
126
+ paintWidth: root.width
127
+ row: cell.live ? root.pane.rowFor(listingIndex) : cell.row
128
+ paneFocused: root.pane.paneFocused
129
+ dualMode: root.pane.dualMode
130
+ hiddenCols: root.rowHiddenCols
131
+ // One Columns.set per List state, shared by every delegate; Row keeps its local default for PickerList and drop targets.
132
+ assignedCols: root.listCols
133
+ hovered: hover.hovered
134
+ thumb: cell.live ? root.thumbFor(listingIndex) : cell.thumb
135
+ selected: cell.live && root.pane.isSelected(listingIndex)
136
+ // Empty short-circuits before the library, so no row calls it while the clipboard is empty.
137
+ clipMark: !cell.live ? cell.clipMark : root.clipEmpty ? "" : ClipMarks.markForRow(root.pane, cell.row ? cell.row.n : "", root.pane.clipboard)
138
+ // Shared budgets: one floor per List state, not per row; drop rows keep local measured geometry in Row.
139
+ assignedNameBudget: cell.clipMark.length > 0 ? root.nameBudgetClip : root.nameBudgetPlain
140
+ // The highlight content builds with the filter strip, so no keystroke pays for it; mirrors the strip's own up rule.
141
+ markArmed: root.pane.filterTyping || root.pane.filterQuery.length > 0
142
+ // A search's location layout builds hidden after the strip's first frame, so no answer pays for it.
143
+ locateArmed: root.pane.searchMode.length > 0 && root.pane.swap.searchWarm === true
144
+ kindNames: cell.live ? root.pane.kindNames : cell.kindNames
145
+ dirSize: cell.live ? DirSizes.cellFor(root.pane.dirSizeState, listingIndex) : cell.dirSize
146
+ // A filter paints its run the same way a search does; filtering below is what keeps the
147
+ // ordinary columns, because these rows are still this directory's own and not walk results.
148
+ searchQuery: !cell.live ? cell.searchQuery : root.pane.searchMode.length > 0 ? root.pane.swap.answeredQuery : root.pane.filterQuery
149
+ filtering: cell.live ? root.pane.shown !== null : cell.filtering
150
+ // Sidebar040: Recent splits its path into Name and the fixed Location column.
151
+ recenting: cell.live ? root.pane.recentMode.length > 0 : cell.recenting
152
+ renaming: listingIndex >= 0 && listingIndex === root.pane.renamingIndex
153
+ renamePane: root.pane
154
+ // -1 is also what Filter.at answers for a stale delegate, so an idle list must never light one.
155
+ dropTarget: dragSession.dropIndex >= 0 && listingIndex === dragSession.dropIndex
156
+ dropCopying: dragSession.dragCopy
157
+ dropLinking: dragSession.dragLink
158
+
159
+ onRenameCommitted: function (newName) { root.pane.commitRename(newName) }
160
+ onRenameAbandoned: root.pane.renamingIndex = -1
161
+
162
+ HoverHandler {
163
+ id: hover
164
+ // Disabled while pooled, so a reused row starts unhovered as a new one does.
165
+ enabled: cell.live && root.pane.selectionBand === null
166
+ }
167
+
168
+ TapHandler {
169
+ id: tap
170
+ enabled: !cell.renaming
171
+ acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
172
+ // A held press must still tap on release.
173
+ longPressThreshold: 0
174
+ // A press held past the interval must not fire while the button is
175
+ // still down on a row about to be dragged; the release still arms.
176
+ onPressedChanged: if (pressed) root.pane.pressSlowClick()
177
+ onTapped: function (eventPoint, button) {
178
+ if (button === Qt.MiddleButton)
179
+ Tap.tappedTab(root.pane.rowFor(listingIndex), root.pane.path, root.pane)
180
+ else if (button === Qt.RightButton)
181
+ Tap.tappedMenu(listingIndex, eventPoint, root.pane, root.menu)
182
+ else if (cell.onSizeCell(eventPoint.position)) {
183
+ // A folder's ⚖️ Size cell measures that folder and does nothing else; a double click stays one ask.
184
+ if (tap.tapCount === 1) root.pane.measureDirs([listingIndex])
185
+ } else {
186
+ var wasSole = root.pane.slowClickWasSole(listingIndex)
187
+ Tap.tapped(listingIndex, tap.tapCount, tap.point.modifiers, root.pane)
188
+ Tap.slowTap(root.pane, tap.tapCount === 1 && Tap.onName(cell.nameItem(), cell, eventPoint.position, false),
189
+ listingIndex, tap.point.modifiers, dragSession.Drag.active, wasSole)
190
+ }
191
+ }
192
+ }
193
+
194
+ Flea.RowDrag {
195
+ session: dragSession
196
+ listingIndex: cell.listingIndex
197
+ row: cell.row
198
+ }
199
+ }
200
+ // The listing keeps one row of bare ground at its end. SearchFilter rule 1 took the filter's
201
+ // sentence off this slot, and the ground under it is not the sentence: it is where a band starts
202
+ // and where the background menu is raised, and a listing whose last row sits flush on the bottom
203
+ // edge offers neither once it is scrolled to the end.
204
+ footer: Item {
205
+ width: root.rowWidth
206
+ height: Theme.chromeHeight
207
+ }
208
+
209
+ // Empty space under the last row belongs to the directory, not to a row, so it raises the
210
+ // background menu. Tap.onBackground says the point missed every delegate, which is what leaves a
211
+ // right click on a row to that row's own handler above.
212
+ TapHandler {
213
+ acceptedButtons: Qt.RightButton
214
+ onTapped: function (eventPoint) {
215
+ if (Tap.onBackground(root, eventPoint))
216
+ root.menu.openBackground(eventPoint.scenePosition)
217
+ }
218
+ }
219
+
220
+ onContentYChanged: {
221
+ // Hidden geometry and a restore in flight move no shared state.
222
+ if (!root.visible || root.hiddenHeld)
223
+ return
224
+ // The cursor follows the bounded view, silent while that view did not move.
225
+ var at = Scroll.bounded(root.contentY, root.originY, root.contentHeight, root.height)
226
+ // Qt shifts originY when expanded delegates collapse; row offsets start at that origin.
227
+ var first = Math.floor((at - root.originY) / Theme.fileRowHeight)
228
+ var last = Math.min(root.pane.shownTotal - 1, first + root.pane.visibleRows - 1)
229
+ if (root.pane.renamingIndex >= 0) {
230
+ var range = root.visibleRange()
231
+ first = range.first
232
+ last = range.last
233
+ }
234
+ if (last >= first && root.pane.selectionBand === null && at !== root._clampAt) {
235
+ root._clampAt = at
236
+ root.cursorClamped(first, last)
237
+ }
238
+ root.menu.close()
239
+ // A scroll never cancels a size the user asked for (src/dirsize.js).
240
+ coalesce.start()
241
+ settle.restart()
242
+ }
243
+
244
+ function visibleRange() {
245
+ var fallback = Thumbs.viewport(root.contentY - root.originY, Theme.fileRowHeight, root.pane.visibleRows, root.pane.shownTotal)
246
+ // The retained error caption expands one row; query actual delegates while it is present.
247
+ if (root.pane.renamingIndex >= 0) {
248
+ var first = root.indexAt(0, root.contentY)
249
+ var last = root.indexAt(0, root.contentY + root.height - 1)
250
+ first = first < 0 ? fallback.first : first
251
+ return {first: first, last: last < 0 ? Math.min(root.count - 1, first + root.pane.visibleRows) : last}
252
+ }
253
+ return fallback
254
+ }
255
+
256
+ // Returning parks the view on the shared cursor once the reset rows land.
257
+ property bool hiddenHeld: false
258
+ // True while the List's own edit is open, so a hide keeps it in any binding order; a rename in Grid or Columns leaves it false.
259
+ property bool renameHeld: false
260
+ // The bounded view last emitted; a bounce holds it, so the cursor stays put.
261
+ property var _clampAt
262
+ // Last parked contentY and loop turns spent; only a value stable across turns ends the hold.
263
+ property real restoreY: -1
264
+ property int restoreTicks: 0
265
+ onVisibleChanged: {
266
+ if (!root.visible) {
267
+ coalesce.stop()
268
+ settle.stop()
269
+ root.hiddenHeld = true
270
+ root.restoreY = -1
271
+ root.restoreTicks = 0
272
+ return
273
+ }
274
+ root.renameHeld = root.pane ? root.pane.renamingIndex >= 0 : false
275
+ if (root.hiddenHeld)
276
+ root.restoreCursorView()
277
+ }
278
+ onCountChanged: {
279
+ if (root.hiddenHeld && root.visible && root.count > 0)
280
+ root.restoreCursorView()
281
+ root.prebuild.landed()
282
+ }
283
+ onCurrentIndexChanged: root.prebuild.kick()
284
+ function restoreCursorView() {
285
+ // A queued turn arriving after the hold ended is stale.
286
+ if (!root.hiddenHeld || !root.visible)
287
+ return
288
+ if (!root.pane) {
289
+ root.hiddenHeld = false
290
+ return
291
+ }
292
+ // The model reset may still be landing; a later turn retries.
293
+ if (root.count === 0 && root.pane.shownTotal > 0) {
294
+ root.deferRestore()
295
+ return
296
+ }
297
+ // An empty listing and a filtered-away cursor have no view to park, so the hold ends here.
298
+ var view = Filter.viewOf(root.pane.shown, root.pane.cursorIndex)
299
+ if (root.count === 0 || view < 0) {
300
+ root.hiddenHeld = false
301
+ return
302
+ }
303
+ root.forceLayout()
304
+ root.positionViewAtIndex(view, ListView.Contain)
305
+ // Only a value stable across turns ends the hold; an optimistic position never releases it.
306
+ if (root.coversCursor(view) && root.contentY === root.restoreY) {
307
+ root.hiddenHeld = false
308
+ root.restoreY = -1
309
+ root.restoreTicks = 0
310
+ settle.restart()
311
+ return
312
+ }
313
+ root.restoreY = root.contentY
314
+ root.deferRestore()
315
+ }
316
+ // The parked check the return asserts through: the cursor row is inside the viewport.
317
+ function coversCursor(view) {
318
+ var top = root.originY + view * Theme.fileRowHeight
319
+ return root.contentY <= top + Theme.fileRowHeight && root.contentY + root.height >= top
320
+ }
321
+ // One more loop turn, with a deadlock guard that ends the hold rather than keeping it.
322
+ function deferRestore() {
323
+ if (!root.visible)
324
+ return
325
+ if (root.restoreTicks >= 60) {
326
+ root.hiddenHeld = false
327
+ root.restoreY = -1
328
+ root.restoreTicks = 0
329
+ settle.restart()
330
+ return
331
+ }
332
+ root.restoreTicks += 1
333
+ Qt.callLater(root.restoreCursorView)
334
+ }
335
+
336
+ // The renaming row's view index, the same mapping restoreCursorView uses.
337
+ readonly property int renameViewIndex: root.pane && root.pane.renamingIndex >= 0 ? Filter.viewOf(root.pane.shown, root.pane.renamingIndex) : -1
338
+ // The renaming delegate's error height, read once here rather than bound per row; none while hidden, when Grid or Columns owns the editor.
339
+ readonly property real renameErrorHeight: {
340
+ if (!root.visible || !root.pane || root.pane.renamingIndex < 0 || root.pane.renameError.length === 0) return 0
341
+ var ed = root.pane.renameEditor()
342
+ var f = ed ? ed.editorField : null
343
+ return f ? f.errorHeight : 0
344
+ }
345
+ // Set when an error line appears or grows, and spent by the view's next contentHeight change.
346
+ property bool containRenameError: false
347
+ onRenameErrorHeightChanged: root.containRenameError = root.renameErrorHeight > 0
348
+ // The error line's growth lands in contentHeight after layout, so the row is contained once then, never on a later scroll's estimate.
349
+ onContentHeightChanged: if (root.containRenameError && root.renameViewIndex >= 0) { root.containRenameError = false; root.positionViewAtIndex(root.renameViewIndex, ListView.Contain) }
350
+
351
+ // Pane's own open() and its Connections.onRows reach these two through the wrapper functions below.
352
+ Timer {
353
+ id: coalesce
354
+ interval: root.pane.coalesceMs
355
+ repeat: false
356
+ onTriggered: root.requestIfDrifted()
357
+ }
358
+
359
+ // The cursor keeps three rows of context above and below while scrolling; every cursor move routes through here.
360
+ function showCursor(view, context) {
361
+ var to = ScrollOff.cursorY(root, view, root.pane.shownTotal, Theme.fileRowHeight, context)
362
+ if (to !== null)
363
+ root.contentY = to
364
+ }
365
+
366
+ // Resize and filter changes can change the visible work without moving contentY.
367
+ Connections {
368
+ target: root.pane
369
+ function onVisibleRowsChanged() { if (root.visible) settle.restart() }
370
+ function onRenamingIndexChanged() { root.renameHeld = root.visible && root.pane.renamingIndex >= 0 }
371
+ function onFilterQueryChanged() {
372
+ if (!root.visible) return
373
+ var work = Filter.cut({ask: [], drop: []}, root.pane.shown, root.pane.thumbState)
374
+ work.drop = work.drop.filter(function(index) { return index !== root.pane.previewIndex })
375
+ if (work.drop.length > 0) {
376
+ root.pane.backend.thumbcancel(work.drop)
377
+ root.thumbsApplied(work)
378
+ }
379
+ // A scroll never cancels a size the user asked for (src/dirsize.js).
380
+ settle.restart()
381
+ }
382
+ }
383
+
384
+ Connections {
385
+ target: ViewState
386
+ function onThumbnailModeChanged() { if (root.visible) settle.restart() }
387
+ // A hidden-then-shown Size column asks for the visible rows at that moment.
388
+ function onHiddenColsChanged() { if (root.visible) settle.restart() }
389
+ }
390
+
391
+ Timer {
392
+ id: settle
393
+ interval: root.pane.firstSettleMs
394
+ repeat: false
395
+ onTriggered: { root.requestThumbs(); root.requestDirSizes() }
396
+ }
397
+
398
+ // Pane.open() primes the next settle to the short first-screen interval before any row arrives.
399
+ function primeSettle() { settle.interval = root.pane.firstSettleMs }
400
+ function restartCoalesce() { coalesce.restart() }
401
+ function restartSettle() { settle.restart() }
402
+
403
+ // Only the visible rows, only once each, and only after the list has stopped moving.
404
+ // Unknown storage holds until fsinfo names it, so the first screen never decodes as local.
405
+ function requestThumbs() {
406
+ if (!root.visible || root.pane.listInFlight || !root.pane.storageKnown)
407
+ return
408
+ var view = root.visibleRange()
409
+ // A filtered viewport covers a set and not a run, so the run it spans is what the planner
410
+ // gets and Filter.cut takes back every row inside that run the filter is hiding.
411
+ var span = Filter.span(root.pane.shown, view.first, view.last)
412
+ var work = Filter.cut(Thumbs.plan(root.pane.thumbState, root.pane.rows, root.pane.held, span.first, span.last, ViewState.thumbnailMode), root.pane.shown, root.pane.thumbState)
413
+ work.drop = work.drop.filter(function (index) { return index !== root.pane.previewIndex })
414
+ root.pane.backend.thumbcancel(work.drop)
415
+ // An off class still asks; the backend answers from the cache alone, see ui/js/ExtThumbs.js.
416
+ work.cacheOnly = ExtThumbs.cacheOnly(root.pane.storageClass, ViewState.preview)
417
+ root.pane.backend.thumb(work.ask, work.cacheOnly)
418
+ // The short first settle latches to the fling debounce only once a request has actually gone out.
419
+ if (work.ask.length > 0)
420
+ settle.interval = root.pane.settleMs
421
+ root.thumbsApplied(work)
422
+ }
423
+
424
+ function thumbFor(index) {
425
+ return Thumbs.allowed(root.pane.rowFor(index), ViewState.thumbnailMode) ? Thumbs.fileFor(root.pane.thumbState, index) : ""
426
+ }
427
+
428
+ function dirSizeFor(index) {
429
+ return DirSizes.sizeFor(root.pane.dirSizeState, index)
430
+ }
431
+
432
+ // Same idiom as requestThumbs, minus a cancel: onContentYChanged already sent it, see above.
433
+ function requestDirSizes() {
434
+ // Folder sizes are measured only when the user asks: a ⚖️ click, see Pane.measureDirs.
435
+ return
436
+ if (!root.visible || root.pane.shownTotal === 0 || root.pane.listInFlight)
437
+ return
438
+ // A hidden Size column or a network or phone folder draws no size, so it asks for no walk.
439
+ if (!DirSizes.wantsSizes("list", ViewState.hiddenCols, root.pane.storageClass, root.pane.storageKnown))
440
+ return
441
+ // Thumbs.viewport() is reused: it takes no thumb-specific state, only geometry.
442
+ var view = root.visibleRange()
443
+ var span = Filter.span(root.pane.shown, view.first, view.last)
444
+ var ask = Filter.keep(DirSizes.plan(root.pane.dirSizeState, root.pane.rows, root.pane.held, span.first, span.last, ViewState.thumbnailMode), root.pane.shown)
445
+ if (ask.length > 0) {
446
+ root.pane.backend.dirsize(ask)
447
+ settle.interval = root.pane.settleMs
448
+ }
449
+ root.dirSizesApplied(ask)
450
+ }
451
+
452
+ // Handle an empty held window explicitly before applying held-edge arithmetic.
453
+ function requestIfDrifted() {
454
+ // No window while hidden, while a filter narrows rows already held, nor while a listing is out, whose windows are the directory asked for.
455
+ if (!root.visible || root.pane.total === 0 || root.pane.shown !== null || root.pane.listInFlight)
456
+ return
457
+ var firstVisible = Math.floor((root.contentY - root.originY) / Theme.fileRowHeight)
458
+ var lastVisible = firstVisible + root.pane.visibleRows
459
+ if (root.pane.renamingIndex >= 0) {
460
+ var range = root.visibleRange()
461
+ firstVisible = range.first
462
+ lastVisible = range.last + 1
463
+ }
464
+ if (root.pane.rows.length === 0) {
465
+ root.requestAround(firstVisible)
466
+ return
467
+ }
468
+ var heldEnd = root.pane.held + root.pane.rows.length
469
+ if (firstVisible - root.pane.held < root.pane.refetchMargin && root.pane.held > 0) {
470
+ root.requestAround(firstVisible)
471
+ } else if (heldEnd - lastVisible < root.pane.refetchMargin && heldEnd < root.pane.total) {
472
+ root.requestAround(firstVisible)
473
+ }
474
+ }
475
+
476
+ function requestAround(firstVisible) {
477
+ var start = Math.max(0, firstVisible - root.pane.buffer)
478
+ root.pane.backend.window(start, root.pane.windowSize)
479
+ }
480
+ }
@@ -0,0 +1,54 @@
1
+ import QtQuick
2
+ import "js/Swap.js" as Swap
3
+
4
+ // The listing's loading touch, EmptyState's sibling: the caller places it over listArea and
5
+ // gates visibility on listingState. The hold-off keeps a local listing, single-digit
6
+ // milliseconds on this box, from ever flashing the mark; only slow sources (network mounts,
7
+ // a cold spinning disk) live long enough to show it.
8
+ Item {
9
+ id: root
10
+
11
+ property int holdOffMs: Swap.HOLD_MS
12
+ property bool armed: false
13
+ // Set when the listing swap already held the old rows for its own cap, which spent this hold-off.
14
+ property bool heldOff: false
15
+ // The mark and its word are on screen; ui/PaneStates.qml tells ui/PaneSwap.qml, which keeps them Swap.MIN_SHOW_MS.
16
+ readonly property bool shown: root.visible && (root.armed || root.heldOff)
17
+ // The crawl's own width, so a Columns pane can tell whether it clears the listed columns.
18
+ readonly property real naturalWidth: crawl.implicitWidth
19
+
20
+ // running binds to visibility rather than an onVisibleChanged handler: the pane starts life
21
+ // in "loading", so visible is true at creation and a change handler would never fire.
22
+ Timer {
23
+ id: holdOff
24
+ interval: root.holdOffMs
25
+ running: root.visible
26
+ onTriggered: root.armed = true
27
+ }
28
+
29
+ onVisibleChanged: if (!root.visible) root.armed = false
30
+
31
+ Column {
32
+ id: crawl
33
+ anchors.centerIn: parent
34
+ spacing: Theme.spacing.gap
35
+ visible: root.armed || root.heldOff
36
+
37
+ Spinner {
38
+ anchors.horizontalCenter: parent.horizontalCenter
39
+ // The same brand mark as EmptyState's hero, which States.dc.html draws at 48; two row heights was 74.
40
+ width: Theme.heroMarkSize
41
+ height: Theme.heroMarkSize
42
+ }
43
+
44
+ // States draws the crawl with one word under it, and one word is the whole of what it knows.
45
+ Text {
46
+ anchors.horizontalCenter: parent.horizontalCenter
47
+ text: "reading"
48
+ color: Theme.color.muted
49
+ font.family: Theme.font.family
50
+ font.pixelSize: Theme.font.caption
51
+ textFormat: Text.PlainText
52
+ }
53
+ }
54
+ }