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,370 @@
1
+ import QtQuick
2
+ import "." as Flea
3
+ import "js/Columns.js" as Columns
4
+ import "js/Facts.js" as Facts
5
+ import "js/Thumbs.js" as Thumbs
6
+ import "js/ExtThumbs.js" as ExtThumbs
7
+ import "js/Keymap.js" as Keymap
8
+ import "js/PreviewKeys.js" as PreviewKeys
9
+ import "js/Search.js" as Search
10
+ import "js/PreviewSettle.js" as PreviewSettle
11
+ import "js/PreviewAsk.js" as PreviewAsk
12
+ import "js/PreviewSwap.js" as PreviewSwap
13
+
14
+ // Selection loading is independent of column visibility and the separate Quick Look overlay.
15
+ Flea.PreviewColumn {
16
+ id: root
17
+ property var pane: null
18
+ property int loadedIndex: -1
19
+ property string loadedDirectory: ""
20
+ property string loadedIdentity: ""
21
+ property int pendingToken: 0
22
+ // ui/ColumnsArea.qml's third-column swap, which then drives the cursor moves; null leaves every change immediate.
23
+ property var swap: null
24
+ property string settleKey: ""
25
+ // The running settle stands for a move the clock stamped and trailed; ColumnsArea's own arm stands for none.
26
+ property bool settleTrails: false
27
+ // A load queued under the swap's picture, so a duplicate replace queues no clear behind it.
28
+ property string loadQueuedKey: ""
29
+ // The multi-selection the loaded frame was built for; "" for a lone selection, which never keys on the version.
30
+ property string loadedSelection: ""
31
+ // Last distinct cursor move, so a held key cannot decode mid-burst: only idleness loads at once.
32
+ property double lastMoveAt: 0
33
+ property string lastMoveKey: ""
34
+ signal thumbsApplied(var work)
35
+ onExpandRequested: {
36
+ if (!root.row || !root.pane) return
37
+ var look = root.pane.quickLook()
38
+ look.open(root.path, root.row.i, root.row.s, root.kindName)
39
+ look.pdfItem.expandFrom(root.pdfPage(), PreviewKeys.PDF_ZOOM_MIN)
40
+ }
41
+
42
+ Keys.onPressed: function(event) {
43
+ var context = root.rowState === Facts.PDF ? "pdf"
44
+ : root.rowState === Facts.VIDEO || root.rowState === Facts.AUDIO ? "media" : "preview"
45
+ var action = Keymap.lookup(event.key, event.text, event.modifiers, context)
46
+ if (action === "escape" || action === "focusPreview") root.pane.listArea.forceActiveFocus()
47
+ else if (PreviewKeys.pageDirection(action)) root.pageBy(PreviewKeys.pageDirection(action))
48
+ else if (action === "loadPreview") root.loadSelection()
49
+ else if (root.rowState === Facts.PDF) PreviewKeys.pdfAction(action, root)
50
+ else if (action === "preview") {
51
+ var strip = root.mediaStripItem()
52
+ if (strip) strip.toggled()
53
+ else if (root.row && !root.row.d) root.pane.quickLook().open(root.path, root.row.i, root.row.s, root.kindName)
54
+ } else if (action === "seekBack" || action === "seekForward") {
55
+ var direction = action === "seekBack" ? -1 : 1
56
+ if (root.rowState === Facts.PDF) root.turnPage(direction)
57
+ else {
58
+ var transport = root.mediaStripItem()
59
+ if (transport) transport.seeked(root.mediaPosition() + direction * PreviewKeys.SEEK_MS)
60
+ }
61
+ } else if (action === "parent") root.turnPage(-1)
62
+ else if (action === "pageForward") root.turnPage(1)
63
+ event.accepted = true
64
+ }
65
+
66
+ readonly property bool canRead: root.visible && root.pane !== null && !root.pane.listInFlight
67
+ overlayOpen: root.pane && root.pane.preview ? root.pane.preview.active : false
68
+ thumb: root.pane ? (root.manualHold ? Thumbs.fileFor(root.pane.thumbState, root.pane.cursorIndex)
69
+ : (root.loadedIndex >= 0 ? Thumbs.fileFor(root.pane.thumbState, root.loadedIndex) : "")) : ""
70
+ noThumbComing: root.row !== null && (root.row.t !== true || !root.pane
71
+ || Thumbs.refused(root.pane.thumbState, root.loadedIndex))
72
+ // True from a move's clear until the next plain clear, the load's own; only then may the swap's fallback end, and its held-off mark show.
73
+ property bool moved: false
74
+ loadingHeldOff: root.swap !== null && root.swap.fellBack && !root.moved
75
+
76
+ // What the swap waits for: the cursor row's preview whole, or nothing more coming for it.
77
+ // A held frame is whole from the listing alone, cached thumbnail or not.
78
+ readonly property bool ready: {
79
+ if (root.manualHold)
80
+ return !root.pending
81
+ // A move's clear writes pending false and then true, and ready must not read true between the two: that ends the swap's fallback at every step of a held key.
82
+ if (root.pane === null || root.row === null)
83
+ return !root.pending && !root.moved
84
+ if (root.loadedIndex !== root.pane.cursorIndex)
85
+ return false
86
+ return PreviewSwap.columnReady({ state: root.previewState, thumb: root.thumb.length > 0,
87
+ frame: root.frameStatus, noThumbComing: root.noThumbComing, pdfDrawn: root.pdfDrawn,
88
+ pdfFailed: root.pdfFailed, linesLoading: root.textLoading, meta: root.meta !== null })
89
+ }
90
+
91
+ // ExtThumbs: how much of a text file this frame may read; the column passes it on.
92
+ textLimit: ExtThumbs.textLimit(root.pane ? root.pane.storageClass : "")
93
+ truncateText: root.pane ? (root.pane.storageClass === "network" || root.pane.storageClass === "phone") : false
94
+
95
+ function identity(row) {
96
+ return row ? JSON.stringify([row.n, row.s, row.m, row.p, row.i]) : ""
97
+ }
98
+
99
+ function swapKey() { return root.pane.path + "\n" + root.pane.cursorIndex }
100
+
101
+ // The settle runs from the key, and a second call for the same row does not push it back.
102
+ function armSettle() {
103
+ if (!ViewState.previewAutomatic || !root.pane)
104
+ return
105
+ var key = root.swapKey()
106
+ if (settle.running && root.settleKey === key)
107
+ return
108
+ root.settleKey = key
109
+ root.settleTrails = false
110
+ settle.restart()
111
+ }
112
+
113
+ function clear() {
114
+ settle.stop()
115
+ root.moved = false
116
+ root.clearShown()
117
+ }
118
+
119
+ // A move's clear: the loading state stands under the swap's picture until the settle loads the new row.
120
+ function clearForMove() {
121
+ root.moved = true
122
+ root.clearShown()
123
+ root.pending = true
124
+ }
125
+
126
+ // A folder or null row keeps the old preview: ColumnsArea holds the old column by data until the peek lands.
127
+ function replace() {
128
+ if (!Columns.isFileRow(root.pane ? root.pane.rowFor(root.pane.cursorIndex) : null)) { settle.stop(); return }
129
+ var key = root.swapKey()
130
+ // A true duplicate preserves the frame and timer; a changed identity lets a same-key refresh proceed.
131
+ // A queued load stands for the same key: clearing behind it would wipe the load when it lands.
132
+ if (key === root.lastMoveKey && (root.isShown() || root.loadQueuedKey === key)) return
133
+ // A burst's move for this key already waits on its settle, so a rows landing under it holds nothing again.
134
+ if (key === root.lastMoveKey && root.moved && settle.running && root.settleKey === key) return
135
+ if (root.swap && ViewState.previewAutomatic && root.canRead) {
136
+ // The picture first, the exact contract a deferred load keeps; the scheduler may load under it at once.
137
+ root.swap.hold(root.clearForMove, key)
138
+ root.settleFor(key)
139
+ return
140
+ }
141
+ if (!root.canRead) { root.clear(); return }
142
+ // No swap takes no picture, so the same scheduler decides after the same duplicate check above.
143
+ root.clear()
144
+ root.settleFor(key)
145
+ }
146
+
147
+ // Whether the loaded frame already names the cursor row: the duplicate test the key clock cannot make.
148
+ function isShown() {
149
+ var current = root.pane.rowFor(root.pane.cursorIndex)
150
+ return root.loadedIndex === root.pane.cursorIndex && root.loadedDirectory === root.pane.path
151
+ && root.loadedIdentity === root.identity(current)
152
+ && root.loadedSelection === PreviewSettle.selectionKey(root.pane.selectionCount(), root.pane.selectionVersion)
153
+ }
154
+
155
+ // Refresh-or-new scheduler: a pending timer already covers this key, otherwise the move clock decides.
156
+ function settleFor(key) {
157
+ if (!ViewState.previewAutomatic || !root.pane) return
158
+ var now = Date.now()
159
+ var decision = PreviewSettle.plan(now, root.lastMoveAt, settle.interval, key, root.lastMoveKey,
160
+ settle.running && root.settleKey === key, root.unrested(key))
161
+ if (decision === "same") return
162
+ root.lastMoveKey = key
163
+ root.lastMoveAt = now
164
+ if (decision === "now") {
165
+ settle.stop()
166
+ root.settleKey = key
167
+ root.fireSettle()
168
+ // Armed once the load's own work returns, work a starved loop can stretch past the settle.
169
+ rested.restart()
170
+ } else {
171
+ root.settleKey = key
172
+ root.settleTrails = true
173
+ settle.restart()
174
+ }
175
+ }
176
+
177
+ function clearShown() {
178
+ root.loadQueuedKey = ""
179
+ root.loadedSelection = ""
180
+ root.pending = false
181
+ root.pendingToken = 0
182
+ root.manualHold = false
183
+ root.loadedIndex = -1
184
+ root.loadedDirectory = ""
185
+ root.loadedIdentity = ""
186
+ root.row = null
187
+ root.meta = null
188
+ root.path = ""
189
+ root.kindName = ""
190
+ root.selectionCount = 0
191
+ root.selectedRows = []
192
+ }
193
+
194
+ function followSelection() {
195
+ if (!root.canRead) return
196
+ var candidate = root.pane.rowFor(root.pane.cursorIndex)
197
+ // Unknown is never held: the class has not named its verdict yet, so the frame waits
198
+ // under the swap's cap and onStorageKnownChanged decides when it lands, never a held mark.
199
+ if (!root.pane.storageKnown) {
200
+ if (root.swap) root.swap.start(false)
201
+ return
202
+ }
203
+ var hold = ExtThumbs.manualHold(root.pane.storageClass, ViewState.preview)
204
+ if (root.loadedDirectory === root.pane.path && root.loadedIndex === root.pane.cursorIndex
205
+ && root.loadedIdentity === root.identity(candidate) && root.manualHold === hold) return
206
+ // A folder or null row keeps the old preview until its peek lands; clearing here would blank the held column.
207
+ if (!Columns.isFileRow(candidate)) { settle.stop(); return }
208
+ // An off class holds the frame on the listing's own facts until Ctrl+Space loads it; nothing loads, so no swap.
209
+ if (hold) { root.clear(); root.holdSelection(candidate); return }
210
+ root.replace()
211
+ }
212
+
213
+ // The held frame: the row, its path and its facts from the listing alone, no meta and no
214
+ // thumbnail ask. The loaded identity is recorded so rows replies do not clear and re-hold.
215
+ // Space still opens Quick Look, which loads on request.
216
+ function holdSelection(candidate) {
217
+ if (!candidate || candidate.d) return
218
+ root.manualHold = true
219
+ root.loadedIndex = root.pane.cursorIndex
220
+ root.loadedDirectory = root.pane.path
221
+ root.loadedIdentity = root.identity(candidate)
222
+ root.row = Object.assign({}, candidate)
223
+ root.path = root.pane.join(Search.baseOf(root.pane), candidate.n)
224
+ root.kindName = root.pane.kindNames[candidate.k] || ""
225
+ root.selectionCount = root.pane.selectionCount()
226
+ root.loadedSelection = PreviewSettle.selectionKey(root.pane.selectionCount(), root.pane.selectionVersion)
227
+ root.selectedRows = root.pane.selectedIndices().map(function (index) { return root.pane.rowFor(index) }).filter(function (row) { return row !== null })
228
+ if (root.swap) root.swap.start(false)
229
+ }
230
+
231
+ // Ctrl+Space calls this directly; automatic selection reaches it only after selection settles.
232
+ function loadSelection() {
233
+ if (!root.canRead) return
234
+ if (!Columns.isFileRow(root.pane.rowFor(root.pane.cursorIndex))) { settle.stop(); return }
235
+ var key = root.swapKey()
236
+ root.loadQueuedKey = key
237
+ if (root.swap) root.swap.hold(root.load, key, true)
238
+ else root.load()
239
+ }
240
+
241
+ // The swap is told the new preview's work has begun, so its cap counts from here, a PDF's after its document settle.
242
+ function load() {
243
+ if (!root.canRead) return
244
+ var pane = root.pane
245
+ var current = pane.rowFor(pane.cursorIndex)
246
+ if (!Columns.isFileRow(current)) { settle.stop(); root.startSwap(false); return }
247
+ root.clear()
248
+ root.loadedIndex = pane.cursorIndex
249
+ root.loadedDirectory = pane.path
250
+ root.loadedIdentity = root.identity(current)
251
+ root.row = Object.assign({}, current)
252
+ root.path = pane.join(Search.baseOf(pane), current.n)
253
+ root.kindName = pane.kindNames[current.k] || ""
254
+ root.selectionCount = pane.selectionCount()
255
+ root.loadedSelection = PreviewSettle.selectionKey(pane.selectionCount(), pane.selectionVersion)
256
+ root.selectedRows = pane.selectedIndices().map(function (index) { return pane.rowFor(index) }).filter(function (row) { return row !== null })
257
+ if (root.selectionCount > 1) { root.startSwap(false); return }
258
+ var kind = Facts.state(current, 1, false, "", root.kindName)
259
+ root.startSwap(kind === Facts.PDF)
260
+ root.pendingToken = pane.backend.askMeta(root.loadedIndex, kind === Facts.TEXT || kind === Facts.CODE,
261
+ kind === Facts.VIDEO || kind === Facts.AUDIO, kind === Facts.ARCHIVE)
262
+ root.askThumb()
263
+ }
264
+
265
+ // The single-row ask, held until the storage class lands: unknown reads as generating,
266
+ // so asking early would thumbnail a NAS image in full over the network.
267
+ function askThumb() {
268
+ var pane = root.pane
269
+ if (!pane || root.loadedIndex < 0) return
270
+ if (root.manualHold || !root.isShown()) return
271
+ var current = pane.rowFor(root.loadedIndex)
272
+ var work = PreviewAsk.workFor({ canRead: root.canRead, storageKnown: pane.storageKnown,
273
+ selectionCount: root.selectionCount, index: root.loadedIndex,
274
+ rowT: current ? !!current.t : false,
275
+ asked: pane.thumbState.file[root.loadedIndex] !== undefined,
276
+ storageClass: pane.storageClass, preview: ViewState.preview })
277
+ if (!work) return
278
+ root.thumbsApplied(work)
279
+ pane.backend.thumb(work.ask, work.cacheOnly)
280
+ }
281
+
282
+ // Idle press asks the cursor thumb before the capture, so load's own ask sends nothing twice.
283
+ function askCursorThumb() {
284
+ if (!ViewState.previewAutomatic || !ViewState.previewColumn) return
285
+ var pane = root.pane
286
+ if (!pane) return
287
+ var current = pane.rowFor(pane.cursorIndex)
288
+ if (!Columns.isFileRow(current)) return
289
+ var key = root.swapKey()
290
+ var work = PreviewAsk.earlyWorkFor({ now: Date.now(), lastMoveAt: root.lastMoveAt,
291
+ interval: settle.interval, key: key, lastMoveKey: root.lastMoveKey,
292
+ armed: settle.running && root.settleKey === key, pending: root.unrested(key), canRead: root.canRead,
293
+ storageKnown: pane.storageKnown, selectionCount: pane.selectionCount(),
294
+ index: pane.cursorIndex, rowT: !!current.t,
295
+ asked: pane.thumbState.file[pane.cursorIndex] !== undefined,
296
+ storageClass: pane.storageClass, preview: ViewState.preview })
297
+ if (!work) return
298
+ root.thumbsApplied(work)
299
+ pane.backend.thumb(work.ask, work.cacheOnly)
300
+ }
301
+
302
+ function startSwap(isPdf) { if (root.swap) root.swap.start(isPdf) }
303
+
304
+ // The settle's whole decision, shared by the timer and the idle fast path, so both spend the same gates.
305
+ function fireSettle() {
306
+ if (!ViewState.previewAutomatic) return
307
+ var hold = root.pane ? (!root.pane.storageKnown || ExtThumbs.manualHold(root.pane.storageClass, ViewState.preview)) : false
308
+ if (hold) root.followSelection()
309
+ else root.loadSelection()
310
+ }
311
+
312
+ // The cursor has not rested since its last move: an earlier row's move still trailing, or a load made at once whose rest has not run out.
313
+ function unrested(key) { return (settle.running && root.settleTrails && root.settleKey !== key) || rested.running }
314
+ // A single-shot Timer stays running until its trigger, a posted event, is handled, so a held key's next repeat that a starved loop
315
+ // handles before then has not rested, however late its own load work made it, and trails instead of loading at once again.
316
+ Timer { id: rested; interval: settle.interval }
317
+ Timer {
318
+ id: settle
319
+ interval: root.pane ? root.pane.settleMs : 120
320
+ // The automatic settle holds an off class; Ctrl+Space's direct loadSelection stays full.
321
+ // Unknown waits through followSelection, so the first settle never spends the class fsinfo has not named yet.
322
+ onTriggered: root.fireSettle()
323
+ }
324
+ onCanReadChanged: {
325
+ // A listing going out leaves the preview to Nav.forget's reset, which clears it when held rows go.
326
+ if (!root.canRead && (!root.visible || root.pane === null)) root.clear()
327
+ else if (root.canRead) root.followSelection()
328
+ }
329
+ Connections {
330
+ target: ViewState
331
+ function onPreviewAutomaticChanged() {
332
+ if (ViewState.previewAutomatic) root.followSelection()
333
+ else settle.stop()
334
+ }
335
+ // A class switch moves the frame between held and loaded without a cursor move.
336
+ function onStateChanged() { root.followSelection() }
337
+ }
338
+ Connections {
339
+ target: root.pane
340
+ // With a swap, ui/ColumnsArea.qml calls followSelection after it has put the hold in place.
341
+ function onCursorIndexChanged() { if (!root.swap) root.followSelection() }
342
+ // The class lands with fsinfo, after the rows; a settle fired in between spent local.
343
+ function onStorageClassChanged() { root.followSelection() }
344
+ // A frame loaded before the class lands never asked; the ask runs here, once the gate names it.
345
+ function onStorageKnownChanged() { root.followSelection(); root.askThumb() }
346
+ function onRowsChanged() {
347
+ if (root.loadedIndex >= 0 && root.loadedIdentity !== root.identity(root.pane.rowFor(root.loadedIndex)))
348
+ root.replace()
349
+ else if (!root.swap)
350
+ root.followSelection()
351
+ }
352
+ function onPathChanged() { root.replace() }
353
+ function onSelectionVersionChanged() { root.replace() }
354
+ }
355
+ Connections {
356
+ target: root.pane ? root.pane.backend : null
357
+ function onMetaResult(message) {
358
+ if (!root.canRead || !root.pendingToken || message.token !== root.pendingToken
359
+ || root.loadedDirectory !== root.pane.path
360
+ || root.loadedIdentity !== root.identity(root.pane.rowFor(root.loadedIndex))) return
361
+ root.pendingToken = 0
362
+ root.meta = { w: message.w, h: message.h, durationMs: message.ms, sampleRate: message.rate,
363
+ entries: message.entries, unpacked: message.unpacked, archiveFailed: message.afailed,
364
+ names: message.names, lines: message.lines, partial: message.partial,
365
+ linesFailed: message.lfailed, target: message.target, targetDir: message.targetdir,
366
+ owner: message.owner || "", orient: message.orient || 1, frames: message.frames || 0, photo: message.photo || null }
367
+ }
368
+ }
369
+ Component.onCompleted: root.followSelection()
370
+ }
@@ -0,0 +1,122 @@
1
+ import QtQuick
2
+ import "." as Flea
3
+ import "js/Format.js" as Format
4
+
5
+ // Favourite records keep their exact label/path; only the drag handle initiates reordering.
6
+ Item {
7
+ id: root
8
+ property var row: ({})
9
+ signal activated()
10
+ signal moved(int to)
11
+ signal removed()
12
+ readonly property Item dragItem: grip
13
+ readonly property Item removeItem: remove
14
+ implicitHeight: Theme.railRowHeight
15
+ // The remove button's accessible name, filled by Format.fill.
16
+ readonly property string removeWord: "Remove %1"
17
+
18
+ Flea.Glyph {
19
+ id: icon
20
+ anchors.left: parent.left
21
+ anchors.leftMargin: Theme.spacing.rowPaddingX
22
+ anchors.verticalCenter: parent.verticalCenter
23
+ // Sidebar040: the Built in rows' own 19 px mark slot, so every label in the pane starts on one column.
24
+ width: Theme.markSize
25
+ height: width
26
+ name: root.row.glyph || "folder"
27
+ color: root.row.error ? Theme.color.error : Theme.color.mutedFrame
28
+ }
29
+ Text {
30
+ anchors.left: icon.right
31
+ anchors.leftMargin: Theme.spacing.gap
32
+ anchors.right: path.left
33
+ anchors.rightMargin: Theme.spacing.gap
34
+ anchors.verticalCenter: parent.verticalCenter
35
+ text: root.row.label || ""
36
+ font.family: Theme.font.family
37
+ font.pixelSize: Theme.font.body
38
+ color: root.row.error ? Theme.color.error : Theme.color.foreground
39
+ elide: Text.ElideRight
40
+ textFormat: Text.PlainText
41
+ }
42
+ Text {
43
+ id: path
44
+ anchors.right: grip.left
45
+ anchors.rightMargin: Theme.spacing.gap
46
+ anchors.verticalCenter: parent.verticalCenter
47
+ width: Math.min(implicitWidth, root.width * 0.46)
48
+ // Sidebar040: a favourite reads as the person writes it; row.value stays the stored path for every action.
49
+ text: root.row.display !== undefined ? root.row.display : (root.row.value || "")
50
+ font.family: Theme.font.family
51
+ font.pixelSize: Theme.font.caption
52
+ color: root.row.error ? Theme.color.error : Theme.color.muted
53
+ elide: Text.ElideMiddle
54
+ textFormat: Text.PlainText
55
+ }
56
+ // SettingsRest rule 4: an action that acts on one row reads as a mark on that row, where a button
57
+ // under the list leaves its target to be inferred from a cursor somewhere above it.
58
+ // Sidebar040: the handle and the remove mark draw at the mark size inside flush 24 px boxes.
59
+ Item {
60
+ id: remove
61
+ anchors.right: parent.right
62
+ anchors.rightMargin: Theme.spacing.rowPaddingX
63
+ anchors.verticalCenter: parent.verticalCenter
64
+ width: Theme.hitMin
65
+ height: Theme.hitMin
66
+ Accessible.role: Accessible.Button
67
+ Accessible.name: Format.fill(root.removeWord, root.row.label || "")
68
+ Accessible.onPressAction: root.removed()
69
+ HoverHandler { cursorShape: Qt.PointingHandCursor }
70
+ TapHandler {
71
+ acceptedButtons: Qt.LeftButton
72
+ gesturePolicy: TapHandler.ReleaseWithinBounds
73
+ onTapped: root.removed()
74
+ }
75
+ Flea.Glyph {
76
+ anchors.centerIn: parent
77
+ width: Theme.markSize
78
+ height: Theme.markSize
79
+ name: "x"
80
+ color: Theme.color.mutedFrame
81
+ }
82
+ }
83
+
84
+ Item {
85
+ id: grip
86
+ anchors.right: remove.left
87
+ anchors.rightMargin: 0
88
+ anchors.verticalCenter: parent.verticalCenter
89
+ width: Theme.hitMin
90
+ height: Theme.hitMin
91
+ Flea.Glyph {
92
+ anchors.centerIn: parent
93
+ width: Theme.markSize
94
+ height: Theme.markSize
95
+ name: "list"
96
+ color: Theme.color.mutedFrame
97
+ }
98
+ DragHandler {
99
+ id: drag
100
+ target: null
101
+ xAxis.enabled: false
102
+ property real startY: 0
103
+ onActiveChanged: {
104
+ if (active) { startY = persistentTranslation.y; return }
105
+ // A pin is a favourite-shaped row ordered inside the shelf's own pile, so the drag
106
+ // counts rows in whichever list this one came from.
107
+ var from = root.row.pinIndex !== undefined ? root.row.pinIndex : root.row.favouriteIndex
108
+ var last = (root.row.pinIndex !== undefined ? root.row.pinCount : Favourites.records.length) - 1
109
+ // Qt clears active translation before this release callback.
110
+ var to = Math.max(0, Math.min(last,
111
+ from + Math.round((persistentTranslation.y - startY) / Theme.railRowHeight)))
112
+ if (to !== from) root.moved(to)
113
+ }
114
+ }
115
+ }
116
+ TapHandler {
117
+ // Exclusive on press so the listing row under the card cannot tap as well; the remove mark
118
+ // owns its corner, so the row still reads where the press landed before it opens anything.
119
+ gesturePolicy: TapHandler.ReleaseWithinBounds
120
+ onTapped: function (point) { if (point.position.x < remove.x) root.activated() }
121
+ }
122
+ }
@@ -0,0 +1,96 @@
1
+ import QtQuick
2
+ import "." as Flea
3
+
4
+ // One settings heading. Where the group has a master, the heading is also that master's control:
5
+ // SettingsMenus rule 3 puts the tri-state box and the group's own enabled count on the heading it
6
+ // governs, so neither is a row of its own and every group answers the question it raises.
7
+ Item {
8
+ id: root
9
+
10
+ // {label, master, state, value} from ui/js/Settings.js, the group row itself.
11
+ property var row: ({})
12
+ property bool first: false
13
+
14
+ // Settings headings scale their resolved 12/15/4/8 insets once from the boards' bodySmall 13 anchor.
15
+ readonly property real insetScale: Theme.font.bodySmall / 13
16
+ readonly property real gap: root.first ? 0 : Math.round(8 * root.insetScale)
17
+ readonly property real paddingTop: Math.round((root.first ? 12 : 15) * root.insetScale)
18
+ readonly property real paddingBottom: Math.round(4 * root.insetScale)
19
+ readonly property bool hasMaster: root.row.master === true
20
+ // SettingsRest rule 3: a group whose one action governs the whole list carries it here instead.
21
+ readonly property bool hasAction: (root.row.action || "") !== ""
22
+
23
+ // Where the heading's own ink starts, under the rule and the padding above its label.
24
+ readonly property real inkTop: label.y
25
+ implicitHeight: label.y + Math.max(label.height, root.hasMaster || root.hasAction ? box.implicitHeight : 0) + root.paddingBottom
26
+
27
+ Text {
28
+ id: label
29
+ anchors.left: parent.left
30
+ anchors.leftMargin: Theme.spacing.rowPaddingX
31
+ y: root.gap + (root.first ? 0 : Theme.spacing.hairline) + root.paddingTop
32
+ height: Theme.font.caption * 1.6 + topPadding
33
+ topPadding: Math.ceil(font.pixelSize * 0.15)
34
+ verticalAlignment: Text.AlignVCenter
35
+ text: root.row.label || ""
36
+ color: Theme.color.muted
37
+ font.family: Theme.font.family
38
+ font.pixelSize: Theme.font.caption
39
+ font.bold: true
40
+ // The canvas sets every group eyebrow in small caps, the same treatment the rail's own headings take.
41
+ font.capitalization: Font.AllUppercase
42
+ font.letterSpacing: Theme.font.caption * 0.14
43
+ textFormat: Text.PlainText
44
+ }
45
+
46
+ Row {
47
+ visible: root.hasAction
48
+ anchors.right: parent.right
49
+ anchors.rightMargin: Theme.spacing.rowPaddingX
50
+ anchors.verticalCenter: label.verticalCenter
51
+ spacing: Theme.spacing.gap - Theme.spacing.hairline
52
+
53
+ Flea.Glyph {
54
+ anchors.verticalCenter: parent.verticalCenter
55
+ width: Theme.font.caption
56
+ height: width
57
+ name: "plus"
58
+ color: Theme.color.foreground
59
+ }
60
+
61
+ Text {
62
+ height: box.implicitHeight
63
+ verticalAlignment: Text.AlignVCenter
64
+ text: root.row.value || ""
65
+ color: Theme.color.foreground
66
+ font.family: Theme.font.family
67
+ font.pixelSize: Theme.font.caption
68
+ textFormat: Text.PlainText
69
+ }
70
+ }
71
+
72
+ Row {
73
+ visible: root.hasMaster
74
+ anchors.right: parent.right
75
+ anchors.rightMargin: Theme.spacing.rowPaddingX
76
+ anchors.verticalCenter: label.verticalCenter
77
+ spacing: Theme.spacing.gap
78
+
79
+ Text {
80
+ height: box.implicitHeight
81
+ verticalAlignment: Text.AlignVCenter
82
+ text: root.row.value || ""
83
+ color: Theme.color.muted
84
+ font.family: Theme.font.family
85
+ font.pixelSize: Theme.font.caption
86
+ font.letterSpacing: Theme.font.caption * 0.14
87
+ textFormat: Text.PlainText
88
+ }
89
+
90
+ // The tri-state the group reads: every id on is a tick, some on a bar, none an empty box.
91
+ Flea.CheckBox {
92
+ id: box
93
+ value: root.row.state === "all" ? "on" : (root.row.state === "some" ? "some" : "off")
94
+ }
95
+ }
96
+ }
@@ -0,0 +1,12 @@
1
+ import QtQuick
2
+
3
+ // A settings hint's type: the caption face, and for a board hint the board's line box of 1.5 times the caption, so a wrapped hint keeps the board's rhythm; the pane's footer line keeps the font's own line.
4
+ Text {
5
+ property bool footer: false
6
+
7
+ font.family: Theme.font.family
8
+ font.pixelSize: Theme.font.caption
9
+ textFormat: Text.PlainText
10
+ lineHeightMode: footer ? Text.ProportionalHeight : Text.FixedHeight
11
+ lineHeight: footer ? 1 : SettingsMetrics.hintLine
12
+ }
@@ -0,0 +1,29 @@
1
+ pragma Singleton
2
+
3
+ import Quickshell
4
+ import QtQuick
5
+
6
+ // The Settings boards' row geometry that CSS derives instead of stating. The boards are drawn at base-size 14, where bodySmall is 13 and the caption 12, so each figure scales with that token as Theme.settings.railPaddingY does.
7
+ Singleton {
8
+ id: root
9
+
10
+ // Tabs040.html data-flea="hint": padding 4px 14px 2px 42px, 12px type, line-height 1.5.
11
+ readonly property int boardHintTop: 4
12
+ readonly property int boardHintBottom: 2
13
+ readonly property real boardHintLineRatio: 1.5
14
+ readonly property int boardBodySmall: 13
15
+
16
+ readonly property int hintTop: Math.round(root.boardHintTop * Theme.font.bodySmall / root.boardBodySmall)
17
+ readonly property int hintBottom: Math.round(root.boardHintBottom * Theme.font.bodySmall / root.boardBodySmall)
18
+ readonly property int hintLine: Math.round(Theme.font.caption * root.boardHintLineRatio)
19
+
20
+ FontMetrics { id: bodyFace; font.family: Theme.font.family; font.pixelSize: Theme.font.body }
21
+ FontMetrics { id: captionFace; font.family: Theme.font.family; font.pixelSize: Theme.font.caption }
22
+
23
+ // A browser puts half of a line's leftover above its text, where a fixed Qt line puts all of it below, so the text box starts this far inside the band and the band's own bottom pad shrinks by it.
24
+ readonly property int hintLead: Math.round((root.hintLine - Math.round(captionFace.ascent) - Math.round(captionFace.descent)) / 2)
25
+
26
+ // A browser centres each line box on the row with its ascent and descent each rounded to whole pixels, so a baseline sits half of ascent less descent below the centre; the caption's baseline therefore sits this far from its label's, 1 px above at 14 over 12 (ClickAndRefresh F7).
27
+ readonly property int captionShift: Math.round(((Math.round(captionFace.ascent) - Math.round(captionFace.descent))
28
+ - (Math.round(bodyFace.ascent) - Math.round(bodyFace.descent))) / 2)
29
+ }