flea-qml 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (637) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +511 -2
  3. package/THIRD-PARTY-NOTICES.md +29 -0
  4. package/demos/App.java +5 -0
  5. package/demos/Dockerfile +4 -0
  6. package/demos/Main.kt +3 -0
  7. package/demos/Program.cs +1 -0
  8. package/demos/README.md +12 -0
  9. package/demos/app.dart +3 -0
  10. package/demos/app.deb +0 -0
  11. package/demos/app.js +1 -0
  12. package/demos/backup.tar +0 -0
  13. package/demos/budget.xlsx +0 -0
  14. package/demos/build.sh +2 -0
  15. package/demos/bundle.zip +0 -0
  16. package/demos/clip.mp4 +0 -0
  17. package/demos/data.sqlite +0 -0
  18. package/demos/disk.iso +0 -0
  19. package/demos/engine.cpp +5 -0
  20. package/demos/firmware.bin +0 -0
  21. package/demos/flake.nix +4 -0
  22. package/demos/folder/inside.txt +1 -0
  23. package/demos/font.ttf +0 -0
  24. package/demos/index.html +5 -0
  25. package/demos/index.php +2 -0
  26. package/demos/init.lua +1 -0
  27. package/demos/letter.docx +0 -0
  28. package/demos/lib.rs +3 -0
  29. package/demos/main.c +6 -0
  30. package/demos/main.h +3 -0
  31. package/demos/math-and-diagrams.md +200 -0
  32. package/demos/notes.tar.gz +0 -0
  33. package/demos/notes.txt +3 -0
  34. package/demos/photo.png +0 -0
  35. package/demos/program +2 -0
  36. package/demos/report.pdf +32 -0
  37. package/demos/script.py +1 -0
  38. package/demos/server.go +7 -0
  39. package/demos/settings.json +4 -0
  40. package/demos/slides.pptx +0 -0
  41. package/demos/song.mp3 +0 -0
  42. package/demos/style.css +4 -0
  43. package/demos/tool.rb +1 -0
  44. package/demos/types.ts +2 -0
  45. package/docs/pele.md +23 -0
  46. package/docs/protocol.md +3420 -0
  47. package/docs/temml.md +63 -0
  48. package/index.js +107 -0
  49. package/package.json +34 -4
  50. package/src/archive.js +407 -0
  51. package/src/archiveops.js +728 -0
  52. package/src/backend.js +369 -0
  53. package/src/bulkrename.js +95 -0
  54. package/src/clip-host.js +76 -0
  55. package/src/clip.js +462 -0
  56. package/src/code.js +168 -0
  57. package/src/compare.js +74 -0
  58. package/src/create.js +128 -0
  59. package/src/dirsize.js +147 -0
  60. package/src/figure-svg.js +530 -0
  61. package/src/figure-thread.js +23 -0
  62. package/src/figure.js +132 -0
  63. package/src/find.js +55 -0
  64. package/src/flea.js +39 -0
  65. package/src/fsinfo.js +39 -0
  66. package/src/highlight.js +141 -0
  67. package/src/html.js +52 -0
  68. package/src/kinds.js +89 -0
  69. package/src/listing.js +130 -0
  70. package/src/markdown-html.js +317 -0
  71. package/src/mathml.js +186 -0
  72. package/src/menu.js +180 -0
  73. package/src/meta.js +135 -0
  74. package/src/office.js +810 -0
  75. package/src/order.js +100 -0
  76. package/src/peek.js +49 -0
  77. package/src/pele-wrapper.js +695 -0
  78. package/src/permissions.js +180 -0
  79. package/src/places.js +313 -0
  80. package/src/preview-language.js +10 -0
  81. package/src/terminal-server.js +95 -0
  82. package/src/terminal-shell.js +26 -0
  83. package/src/transfer.js +669 -0
  84. package/src/trash-record.js +41 -0
  85. package/src/trash.js +210 -0
  86. package/src/trashbrowse.js +327 -0
  87. package/src/uistate.js +393 -0
  88. package/src/uistore.js +168 -0
  89. package/src/vendor/LICENSES/Apache-2.0.txt +202 -0
  90. package/src/vendor/LICENSES/MIT-katex-2015.txt +27 -0
  91. package/src/vendor/LICENSES/MIT-katex.txt +21 -0
  92. package/src/vendor/LICENSES/MIT-mermaid.txt +21 -0
  93. package/src/vendor/LICENSES/MIT-pele.txt +40 -0
  94. package/src/vendor/LICENSES/MIT-perseus.txt +18 -0
  95. package/src/vendor/LICENSES/MIT-temml.txt +21 -0
  96. package/src/vendor/pele.js +145 -0
  97. package/src/vendor/temml.mjs +14708 -0
  98. package/src/watch.js +98 -0
  99. package/src/wayland/client.js +109 -0
  100. package/src/wayland/protocol.js +55 -0
  101. package/src/wayland/protocols/ext-data-control-v1.xml +276 -0
  102. package/src/wayland/protocols/wayland.xml +3248 -0
  103. package/src/wayland/protocols/wlr-data-control-unstable-v1.xml +278 -0
  104. package/src/wayland/resource-io.js +6 -0
  105. package/src/wayland/socket-discovery.js +26 -0
  106. package/src/wayland/transport-posix.js +120 -0
  107. package/src/wayland/transport-win32.js +11 -0
  108. package/src/wayland/transport.js +3 -0
  109. package/src/wayland/win32-resources.js +80 -0
  110. package/src/wayland/win32-wire.js +62 -0
  111. package/test/archive.test.js +80 -0
  112. package/test/bench-markdown-scroll.mjs +190 -0
  113. package/test/clip-host.test.js +113 -0
  114. package/test/code-preview.test.js +35 -0
  115. package/test/compare-ui-paths.test.js +24 -0
  116. package/test/compare.test.js +54 -0
  117. package/test/delete-trash.test.js +67 -0
  118. package/test/dirsize.test.js +138 -0
  119. package/test/file-ops.test.js +307 -0
  120. package/test/file-url.test.js +24 -0
  121. package/test/find-contents.test.js +161 -0
  122. package/test/find-input.test.js +66 -0
  123. package/test/fixtures/pele-parity.json +1006 -0
  124. package/test/highlight-launcher.test.js +35 -0
  125. package/test/html-preview.test.js +22 -0
  126. package/test/input.test.js +15 -0
  127. package/test/keymap.test.js +26 -0
  128. package/test/language-icons.test.js +36 -0
  129. package/test/launcher.test.js +51 -0
  130. package/test/manual-archive-here-ui.mjs +47 -0
  131. package/test/manual-code-scroll.mjs +28 -0
  132. package/test/manual-column-scroll.mjs +24 -0
  133. package/test/manual-compare-ui.mjs +20 -0
  134. package/test/manual-find-status.mjs +37 -0
  135. package/test/manual-folder-focus.mjs +63 -0
  136. package/test/manual-html-security.mjs +23 -0
  137. package/test/manual-html-ui.mjs +30 -0
  138. package/test/manual-syntax-preview.mjs +26 -0
  139. package/test/manual-terminal-lifecycle.mjs +42 -0
  140. package/test/manual-terminal-navigation.mjs +48 -0
  141. package/test/manual-terminal-ui.mjs +47 -0
  142. package/test/manual-trash-ui.mjs +86 -0
  143. package/test/markdown-diagrams.test.js +93 -0
  144. package/test/markdown-html.test.js +105 -0
  145. package/test/mathml.test.js +92 -0
  146. package/test/menu-transfer.test.js +57 -0
  147. package/test/office-preview.test.js +154 -0
  148. package/test/pele-parity.test.js +28 -0
  149. package/test/places.test.js +134 -0
  150. package/test/preview-keys.test.js +60 -0
  151. package/test/preview-language.test.js +22 -0
  152. package/test/status-filename.test.js +20 -0
  153. package/test/transfer-replace-merge.test.js +187 -0
  154. package/test/trash-address.test.js +23 -0
  155. package/test/trash-view.test.js +37 -0
  156. package/test/trashbrowse.test.js +135 -0
  157. package/ui/AboutFacts.qml +78 -0
  158. package/ui/ArchiveCards.qml +95 -0
  159. package/ui/ArchiveCompressDialog.qml +378 -0
  160. package/ui/ArchiveHereConfirm.qml +127 -0
  161. package/ui/ArchivePasswordDialog.qml +257 -0
  162. package/ui/Backend.qml +775 -0
  163. package/ui/BulkOldNames.qml +47 -0
  164. package/ui/BulkRenameDialog.qml +380 -0
  165. package/ui/CardFrame.qml +67 -0
  166. package/ui/CardScroll.qml +79 -0
  167. package/ui/CheckBox.qml +73 -0
  168. package/ui/ChromeBar.qml +360 -0
  169. package/ui/ChromeButton.qml +131 -0
  170. package/ui/ChromeModes.qml +43 -0
  171. package/ui/CodeLines.qml +256 -0
  172. package/ui/CodeRefusal.qml +52 -0
  173. package/ui/CollideConfirm.qml +147 -0
  174. package/ui/CollideHost.qml +167 -0
  175. package/ui/ColumnPane.qml +525 -0
  176. package/ui/ColumnRow.qml +380 -0
  177. package/ui/ColumnsArea.qml +594 -0
  178. package/ui/ColumnsLanding.qml +147 -0
  179. package/ui/CompareView.qml +321 -0
  180. package/ui/ContextMenu.qml +743 -0
  181. package/ui/ConvertDialog.qml +456 -0
  182. package/ui/CountedWorker.qml +7 -0
  183. package/ui/Crumb.qml +64 -0
  184. package/ui/CrumbDrop.qml +25 -0
  185. package/ui/CsvTable.qml +394 -0
  186. package/ui/CursorMark.qml +41 -0
  187. package/ui/DefaultClaim.qml +130 -0
  188. package/ui/DeviceLock.qml +47 -0
  189. package/ui/DeviceMounts.qml +540 -0
  190. package/ui/DialogButton.qml +150 -0
  191. package/ui/DialogField.qml +147 -0
  192. package/ui/DialogHeader.qml +31 -0
  193. package/ui/DialogScrim.qml +20 -0
  194. package/ui/DialogTitle.qml +37 -0
  195. package/ui/Divider.qml +9 -0
  196. package/ui/DropInto.qml +126 -0
  197. package/ui/DropTarget.qml +35 -0
  198. package/ui/DropboxMark.qml +60 -0
  199. package/ui/EmptyState.qml +150 -0
  200. package/ui/EscapeHint.qml +11 -0
  201. package/ui/FactsTable.qml +54 -0
  202. package/ui/FastScrollHandler.qml +476 -0
  203. package/ui/FatNamesConfirm.qml +157 -0
  204. package/ui/Favourites.qml +143 -0
  205. package/ui/FigureService.qml +120 -0
  206. package/ui/FileDrag.qml +267 -0
  207. package/ui/FilterStrip.qml +133 -0
  208. package/ui/FitMetrics.qml +22 -0
  209. package/ui/FlashDriveRows.qml +137 -0
  210. package/ui/FlashHost.qml +72 -0
  211. package/ui/FlashImageRow.qml +104 -0
  212. package/ui/FlashRunner.qml +119 -0
  213. package/ui/FlashStepRow.qml +172 -0
  214. package/ui/FlashStrip.qml +38 -0
  215. package/ui/FlashView.qml +397 -0
  216. package/ui/FleaMark.qml +88 -0
  217. package/ui/FlyoutFade.qml +23 -0
  218. package/ui/FontPane.qml +170 -0
  219. package/ui/Glass.qml +114 -0
  220. package/ui/GlassTagger.qml +59 -0
  221. package/ui/Glyph.qml +64 -0
  222. package/ui/GlyphSolid.qml +22 -0
  223. package/ui/GridArea.qml +664 -0
  224. package/ui/GridTile.qml +325 -0
  225. package/ui/GvfsBridge.qml +164 -0
  226. package/ui/Header.qml +433 -0
  227. package/ui/HoverTimers.qml +39 -0
  228. package/ui/HtmlClip.qml +30 -0
  229. package/ui/HtmlPane.qml +63 -0
  230. package/ui/HyprlandMark.qml +45 -0
  231. package/ui/Ipc.qml +1005 -0
  232. package/ui/IpcControls.qml +7 -0
  233. package/ui/IpcMenuState.qml +48 -0
  234. package/ui/IpcPreviewState.qml +185 -0
  235. package/ui/JumpPath.qml +51 -0
  236. package/ui/KeymapSheet.qml +561 -0
  237. package/ui/KeymapSheetResult.qml +89 -0
  238. package/ui/KindStack.qml +40 -0
  239. package/ui/LangMark.qml +51 -0
  240. package/ui/LangMarkLoader.qml +26 -0
  241. package/ui/List.qml +480 -0
  242. package/ui/LoadingState.qml +54 -0
  243. package/ui/LocalSend.qml +56 -0
  244. package/ui/LocalSendMark.qml +73 -0
  245. package/ui/MarkdownBlockView.qml +311 -0
  246. package/ui/MarkdownBlocks.qml +35 -0
  247. package/ui/MarkdownFigure.qml +254 -0
  248. package/ui/MarkdownImages.qml +72 -0
  249. package/ui/MarkdownList.qml +81 -0
  250. package/ui/MarkdownMathsText.qml +97 -0
  251. package/ui/MarkdownPane.qml +83 -0
  252. package/ui/MarkdownPictures.qml +41 -0
  253. package/ui/MarkdownQuote.qml +52 -0
  254. package/ui/MarkdownRemote.qml +82 -0
  255. package/ui/MarkdownSource.qml +155 -0
  256. package/ui/MarkdownTable.qml +222 -0
  257. package/ui/MarkdownTableScroll.qml +64 -0
  258. package/ui/MarkdownTableWheel.qml +126 -0
  259. package/ui/MarkdownText.qml +87 -0
  260. package/ui/MarkdownWorker.js +132 -0
  261. package/ui/MatchText.qml +99 -0
  262. package/ui/MediaSession.qml +38 -0
  263. package/ui/MediaSound.qml +26 -0
  264. package/ui/MediaStrip.qml +191 -0
  265. package/ui/MediaTrack.qml +36 -0
  266. package/ui/MediaVolume.qml +54 -0
  267. package/ui/MenuActionDialog.qml +396 -0
  268. package/ui/MenuEdgeFade.qml +24 -0
  269. package/ui/MenuHost.qml +227 -0
  270. package/ui/MenuRow.qml +351 -0
  271. package/ui/MountListing.qml +100 -0
  272. package/ui/NetworkDialog.qml +435 -0
  273. package/ui/NetworkForm.qml +426 -0
  274. package/ui/NetworkMounts.qml +913 -0
  275. package/ui/NetworkPlaces.qml +127 -0
  276. package/ui/OpenWithDialog.qml +613 -0
  277. package/ui/Opener.qml +95 -0
  278. package/ui/Pane.qml +1320 -0
  279. package/ui/PaneMenuActions.qml +527 -0
  280. package/ui/PanePath.qml +90 -0
  281. package/ui/PaneRail.qml +268 -0
  282. package/ui/PaneStates.qml +88 -0
  283. package/ui/PaneSwap.qml +339 -0
  284. package/ui/PaneWire.qml +601 -0
  285. package/ui/ParkedWait.qml +9 -0
  286. package/ui/PathEntry.qml +186 -0
  287. package/ui/PathJump.qml +400 -0
  288. package/ui/PdfViewer.qml +297 -0
  289. package/ui/PermissionsDialog.qml +658 -0
  290. package/ui/PermissionsHeadings.qml +31 -0
  291. package/ui/PhoneMounts.qml +67 -0
  292. package/ui/PickerAnswers.qml +75 -0
  293. package/ui/PickerBox.qml +26 -0
  294. package/ui/PickerChrome.qml +295 -0
  295. package/ui/PickerFilter.qml +97 -0
  296. package/ui/PickerGrid.qml +308 -0
  297. package/ui/PickerHeader.qml +28 -0
  298. package/ui/PickerLifecycle.qml +27 -0
  299. package/ui/PickerList.qml +218 -0
  300. package/ui/PickerListing.qml +149 -0
  301. package/ui/PickerPathBar.qml +127 -0
  302. package/ui/PickerPlaces.qml +189 -0
  303. package/ui/PickerRecent.qml +92 -0
  304. package/ui/PickerSave.qml +101 -0
  305. package/ui/PickerSelection.qml +155 -0
  306. package/ui/PickerWindow.qml +846 -0
  307. package/ui/PowerSectorsReader.qml +10 -0
  308. package/ui/PrebuildDriver.qml +146 -0
  309. package/ui/Preview.qml +1005 -0
  310. package/ui/PreviewAnimation.qml +24 -0
  311. package/ui/PreviewArchive.qml +91 -0
  312. package/ui/PreviewColumn.qml +553 -0
  313. package/ui/PreviewEdge.qml +63 -0
  314. package/ui/PreviewFacts.qml +30 -0
  315. package/ui/PreviewFactsLine.qml +34 -0
  316. package/ui/PreviewHtml.qml +233 -0
  317. package/ui/PreviewImage.qml +253 -0
  318. package/ui/PreviewImagePan.qml +13 -0
  319. package/ui/PreviewImageSharp.qml +32 -0
  320. package/ui/PreviewLines.qml +106 -0
  321. package/ui/PreviewMarkdown.qml +706 -0
  322. package/ui/PreviewMedia.qml +250 -0
  323. package/ui/PreviewPdf.qml +482 -0
  324. package/ui/PreviewScroll.qml +201 -0
  325. package/ui/PreviewSwap.qml +335 -0
  326. package/ui/PreviewText.qml +149 -0
  327. package/ui/ProtocolChip.qml +18 -0
  328. package/ui/QuickLookArchive.qml +41 -0
  329. package/ui/QuickLookBar.qml +103 -0
  330. package/ui/QuickLookPrepare.qml +355 -0
  331. package/ui/QuickLookSwap.qml +10 -0
  332. package/ui/QuickLookWarm.qml +65 -0
  333. package/ui/RailDrop.qml +155 -0
  334. package/ui/RailHeading.qml +19 -0
  335. package/ui/RailPlaces.qml +38 -0
  336. package/ui/RailTrashRow.qml +67 -0
  337. package/ui/RenameField.qml +353 -0
  338. package/ui/RendererRetry.qml +11 -0
  339. package/ui/ResizeHandle.qml +52 -0
  340. package/ui/Reveal.qml +54 -0
  341. package/ui/Row.qml +476 -0
  342. package/ui/RowDrag.qml +213 -0
  343. package/ui/RowDropTarget.qml +27 -0
  344. package/ui/RunCard.qml +286 -0
  345. package/ui/Scripts.qml +65 -0
  346. package/ui/SearchStrip.qml +232 -0
  347. package/ui/SelectionBand.qml +140 -0
  348. package/ui/SelectionPreview.qml +370 -0
  349. package/ui/SettingsFavourite.qml +122 -0
  350. package/ui/SettingsGroup.qml +96 -0
  351. package/ui/SettingsHint.qml +12 -0
  352. package/ui/SettingsMetrics.qml +29 -0
  353. package/ui/SettingsPane.qml +178 -0
  354. package/ui/SettingsPanel.qml +547 -0
  355. package/ui/SettingsRail.qml +128 -0
  356. package/ui/SettingsRow.qml +409 -0
  357. package/ui/SettingsRuler.qml +85 -0
  358. package/ui/SettingsSegment.qml +85 -0
  359. package/ui/ShareBrowser.qml +113 -0
  360. package/ui/ShareLink.qml +67 -0
  361. package/ui/ShelfPins.qml +101 -0
  362. package/ui/Sidebar.qml +728 -0
  363. package/ui/SidebarRow.qml +358 -0
  364. package/ui/Spinner.qml +60 -0
  365. package/ui/StableModel.qml +89 -0
  366. package/ui/StateMessage.qml +84 -0
  367. package/ui/StatusBar.qml +512 -0
  368. package/ui/StatusFileName.qml +27 -0
  369. package/ui/TabBar.qml +673 -0
  370. package/ui/TabDragGeometry.qml +60 -0
  371. package/ui/TagMenuMark.qml +52 -0
  372. package/ui/TagRailSection.qml +53 -0
  373. package/ui/TagSlot.qml +40 -0
  374. package/ui/TagState.qml +150 -0
  375. package/ui/TagSwatch.qml +28 -0
  376. package/ui/Taildrop.qml +86 -0
  377. package/ui/TailscaleMark.qml +50 -0
  378. package/ui/TerminalService.qml +69 -0
  379. package/ui/TerminalTab.qml +48 -0
  380. package/ui/TerminalTabs.qml +27 -0
  381. package/ui/Theme.qml +460 -0
  382. package/ui/ThemeColors.qml +43 -0
  383. package/ui/TransferCard.qml +239 -0
  384. package/ui/TrashConfirm.qml +129 -0
  385. package/ui/TrashDropHandler.qml +11 -0
  386. package/ui/TrashHost.qml +202 -0
  387. package/ui/TrashMonitor.qml +30 -0
  388. package/ui/TrashToolbar.qml +19 -0
  389. package/ui/TrashView.qml +492 -0
  390. package/ui/UnlockDialog.qml +450 -0
  391. package/ui/UnlockHost.qml +206 -0
  392. package/ui/UpdateCheck.qml +97 -0
  393. package/ui/UserDirs.qml +25 -0
  394. package/ui/ViewState.qml +565 -0
  395. package/ui/ViewportScrollBar.qml +195 -0
  396. package/ui/ViewportScrollBars.qml +25 -0
  397. package/ui/WebPreview.qml +33 -0
  398. package/ui/WebPreviewView.qml +26 -0
  399. package/ui/WindowBody.qml +829 -0
  400. package/ui/WindowDrag.qml +35 -0
  401. package/ui/boot/Commons/AudioNodes.qml +50 -0
  402. package/ui/boot/Commons/AudioNodesModel.js +96 -0
  403. package/ui/boot/Commons/Border.qml +243 -0
  404. package/ui/boot/Commons/BorderGeometry.js +373 -0
  405. package/ui/boot/Commons/Color.qml +258 -0
  406. package/ui/boot/Commons/I18n.qml +118 -0
  407. package/ui/boot/Commons/InputDevices.qml +112 -0
  408. package/ui/boot/Commons/InputMethodState.qml +38 -0
  409. package/ui/boot/Commons/IpcRegistry.qml +77 -0
  410. package/ui/boot/Commons/Numbers.js +19 -0
  411. package/ui/boot/Commons/Plural.js +91 -0
  412. package/ui/boot/Commons/ShellIpc.qml +12 -0
  413. package/ui/boot/Commons/Style.qml +561 -0
  414. package/ui/boot/Commons/Translations.qml +100 -0
  415. package/ui/boot/Commons/UntypedInput.qml +152 -0
  416. package/ui/boot/Commons/Util.qml +188 -0
  417. package/ui/boot/Commons/qmldir +13 -0
  418. package/ui/boot/LICENSE-omarchy +20 -0
  419. package/ui/boot/Ui/BackgroundMedia.qml +49 -0
  420. package/ui/boot/Ui/BarIconButton.qml +106 -0
  421. package/ui/boot/Ui/BarIconContent.qml +38 -0
  422. package/ui/boot/Ui/BarIndicator.qml +53 -0
  423. package/ui/boot/Ui/BarWidget.qml +50 -0
  424. package/ui/boot/Ui/BorderOverlay.qml +54 -0
  425. package/ui/boot/Ui/BorderSurface.qml +40 -0
  426. package/ui/boot/Ui/Button.qml +224 -0
  427. package/ui/boot/Ui/ButtonGroup.qml +131 -0
  428. package/ui/boot/Ui/ConfirmDialog.qml +134 -0
  429. package/ui/boot/Ui/CursorSurface.qml +42 -0
  430. package/ui/boot/Ui/Dropdown.qml +245 -0
  431. package/ui/boot/Ui/FilterInput.qml +26 -0
  432. package/ui/boot/Ui/IconContentBounds.qml +141 -0
  433. package/ui/boot/Ui/KeyboardPanel.qml +453 -0
  434. package/ui/boot/Ui/MultiSelect.qml +624 -0
  435. package/ui/boot/Ui/NumberField.qml +86 -0
  436. package/ui/boot/Ui/OpticalGlyph.qml +68 -0
  437. package/ui/boot/Ui/OverlayWindow.qml +102 -0
  438. package/ui/boot/Ui/Panel.qml +60 -0
  439. package/ui/boot/Ui/PanelActionButton.qml +105 -0
  440. package/ui/boot/Ui/PanelController.qml +16 -0
  441. package/ui/boot/Ui/PanelHero.qml +112 -0
  442. package/ui/boot/Ui/PanelKeyCatcher.qml +100 -0
  443. package/ui/boot/Ui/PanelSectionHeader.qml +31 -0
  444. package/ui/boot/Ui/PanelSeparator.qml +19 -0
  445. package/ui/boot/Ui/PanelSlider.qml +156 -0
  446. package/ui/boot/Ui/PanelToolTip.qml +50 -0
  447. package/ui/boot/Ui/PluginBarApi.qml +89 -0
  448. package/ui/boot/Ui/PointerMoveGate.qml +54 -0
  449. package/ui/boot/Ui/PopupCard.qml +181 -0
  450. package/ui/boot/Ui/ScreenMoveRemap.qml +43 -0
  451. package/ui/boot/Ui/SearchableDropdown.qml +354 -0
  452. package/ui/boot/Ui/SizedImage.qml +125 -0
  453. package/ui/boot/Ui/SpeedTestOverlay.qml +412 -0
  454. package/ui/boot/Ui/TextField.qml +58 -0
  455. package/ui/boot/Ui/Toggle.qml +118 -0
  456. package/ui/boot/Ui/ToggleSwitch.qml +115 -0
  457. package/ui/boot/Ui/WidgetButton.qml +172 -0
  458. package/ui/boot/Ui/qmldir +41 -0
  459. package/ui/boot/fleatab.qml +50 -0
  460. package/ui/boot/picker.qml +39 -0
  461. package/ui/boot/shell.qml +131 -0
  462. package/ui/boot/tabtearoff.qml +51 -0
  463. package/ui/js/Anchor.js +379 -0
  464. package/ui/js/AnchorHold.js +162 -0
  465. package/ui/js/Archive.js +157 -0
  466. package/ui/js/ArchiveCard.js +44 -0
  467. package/ui/js/ArchiveOps.js +44 -0
  468. package/ui/js/BackReturn.js +118 -0
  469. package/ui/js/BulkRename.js +100 -0
  470. package/ui/js/Buttons.js +54 -0
  471. package/ui/js/ChromeKeys.js +116 -0
  472. package/ui/js/ClipMarks.js +73 -0
  473. package/ui/js/ClipSelection.js +67 -0
  474. package/ui/js/Clipboard.js +179 -0
  475. package/ui/js/Cloud.js +97 -0
  476. package/ui/js/CodeRuns.js +72 -0
  477. package/ui/js/Collide.js +212 -0
  478. package/ui/js/ColumnFit.js +28 -0
  479. package/ui/js/ColumnMenu.js +111 -0
  480. package/ui/js/Columns.js +298 -0
  481. package/ui/js/ColumnsCarry.js +103 -0
  482. package/ui/js/Compare.js +74 -0
  483. package/ui/js/Contrast.js +157 -0
  484. package/ui/js/ControlReader.js +42 -0
  485. package/ui/js/Convert.js +52 -0
  486. package/ui/js/CopyAs.js +52 -0
  487. package/ui/js/Crumbs.js +178 -0
  488. package/ui/js/Csv.js +231 -0
  489. package/ui/js/Density.js +44 -0
  490. package/ui/js/Devices.js +440 -0
  491. package/ui/js/DirSizes.js +180 -0
  492. package/ui/js/Drag.js +360 -0
  493. package/ui/js/DragOut.js +166 -0
  494. package/ui/js/DropDev.js +52 -0
  495. package/ui/js/Dropbox.js +41 -0
  496. package/ui/js/Eject.js +217 -0
  497. package/ui/js/Errors.js +188 -0
  498. package/ui/js/ExtThumbs.js +115 -0
  499. package/ui/js/Facts.js +402 -0
  500. package/ui/js/FigureDate.js +14 -0
  501. package/ui/js/Filter.js +285 -0
  502. package/ui/js/Find.js +46 -0
  503. package/ui/js/Flash.js +184 -0
  504. package/ui/js/FlashCard.js +79 -0
  505. package/ui/js/FlashEndings.js +125 -0
  506. package/ui/js/FlashPane.js +116 -0
  507. package/ui/js/FleaBin.js +12 -0
  508. package/ui/js/Focus.js +504 -0
  509. package/ui/js/FolderSorts.js +108 -0
  510. package/ui/js/FolderViews.js +44 -0
  511. package/ui/js/Format.js +314 -0
  512. package/ui/js/Fuzzy.js +141 -0
  513. package/ui/js/GlassTag.js +72 -0
  514. package/ui/js/Grid.js +33 -0
  515. package/ui/js/GridGeometry.js +90 -0
  516. package/ui/js/GridNames.js +153 -0
  517. package/ui/js/GvfsBridge.js +200 -0
  518. package/ui/js/HostClipboard.js +29 -0
  519. package/ui/js/Icons.js +218 -0
  520. package/ui/js/Input.js +50 -0
  521. package/ui/js/Jump.js +200 -0
  522. package/ui/js/KeyName.js +64 -0
  523. package/ui/js/Keymap.js +401 -0
  524. package/ui/js/Kinds.js +164 -0
  525. package/ui/js/LICENSES/ISC-lucide.txt +43 -0
  526. package/ui/js/LangMarkPaths.js +47 -0
  527. package/ui/js/LangMarks.js +120 -0
  528. package/ui/js/Lists.js +11 -0
  529. package/ui/js/LocalSend.js +39 -0
  530. package/ui/js/LockedMenu.js +63 -0
  531. package/ui/js/MakeDefault.js +186 -0
  532. package/ui/js/MarkBox.js +7 -0
  533. package/ui/js/Markdown.js +119 -0
  534. package/ui/js/MarkdownLists.js +86 -0
  535. package/ui/js/MarkdownMaths.js +58 -0
  536. package/ui/js/MarkdownPictures.js +32 -0
  537. package/ui/js/MarkdownPrepared.js +139 -0
  538. package/ui/js/MarkdownTableFit.js +34 -0
  539. package/ui/js/Marks.js +148 -0
  540. package/ui/js/Marquee.js +96 -0
  541. package/ui/js/Match.js +93 -0
  542. package/ui/js/Material.js +109 -0
  543. package/ui/js/MdBlocks.js +437 -0
  544. package/ui/js/MdBreak.js +71 -0
  545. package/ui/js/MdChunks.js +70 -0
  546. package/ui/js/MdContainer.js +137 -0
  547. package/ui/js/MdDocument.js +337 -0
  548. package/ui/js/MdEmph.js +97 -0
  549. package/ui/js/MdEntity.js +108 -0
  550. package/ui/js/MdEntityTable.js +223 -0
  551. package/ui/js/MdEscape.js +59 -0
  552. package/ui/js/MdFront.js +37 -0
  553. package/ui/js/MdHold.js +32 -0
  554. package/ui/js/MdHtml.js +307 -0
  555. package/ui/js/MdHtmlBlock.js +290 -0
  556. package/ui/js/MdHtmlHeading.js +53 -0
  557. package/ui/js/MdHtmlImage.js +179 -0
  558. package/ui/js/MdInline.js +154 -0
  559. package/ui/js/MdItems.js +212 -0
  560. package/ui/js/MdLeaf.js +309 -0
  561. package/ui/js/MdLink.js +196 -0
  562. package/ui/js/MdMath.js +67 -0
  563. package/ui/js/MdParagraphs.js +138 -0
  564. package/ui/js/MdRefs.js +232 -0
  565. package/ui/js/MdResolve.js +226 -0
  566. package/ui/js/MdRun.js +300 -0
  567. package/ui/js/MdUrl.js +226 -0
  568. package/ui/js/Menu.js +514 -0
  569. package/ui/js/MenuContext.js +85 -0
  570. package/ui/js/MenuFit.js +13 -0
  571. package/ui/js/MenuRefresh.js +74 -0
  572. package/ui/js/MenuWheel.js +35 -0
  573. package/ui/js/Messages.js +186 -0
  574. package/ui/js/Motion.js +16 -0
  575. package/ui/js/Mounts.js +320 -0
  576. package/ui/js/MouseNav.js +13 -0
  577. package/ui/js/Nav.js +329 -0
  578. package/ui/js/NetFs.js +26 -0
  579. package/ui/js/OpenWith.js +83 -0
  580. package/ui/js/Ops.js +585 -0
  581. package/ui/js/Palette.js +33 -0
  582. package/ui/js/PathBar.js +260 -0
  583. package/ui/js/Permissions.js +179 -0
  584. package/ui/js/Phones.js +112 -0
  585. package/ui/js/Picker.js +353 -0
  586. package/ui/js/PlaceMenu.js +96 -0
  587. package/ui/js/Places.js +265 -0
  588. package/ui/js/PreviewAsk.js +21 -0
  589. package/ui/js/PreviewKeys.js +155 -0
  590. package/ui/js/PreviewSettle.js +29 -0
  591. package/ui/js/PreviewSwap.js +101 -0
  592. package/ui/js/PropertyFacts.js +144 -0
  593. package/ui/js/Protocols.js +296 -0
  594. package/ui/js/QuickLookKinds.js +27 -0
  595. package/ui/js/QuickLookRect.js +24 -0
  596. package/ui/js/RailDrop.js +51 -0
  597. package/ui/js/RailKeys.js +87 -0
  598. package/ui/js/RailMenu.js +133 -0
  599. package/ui/js/Recent.js +135 -0
  600. package/ui/js/RecentMode.js +156 -0
  601. package/ui/js/Reload.js +60 -0
  602. package/ui/js/Renderer.js +9 -0
  603. package/ui/js/RunFile.js +143 -0
  604. package/ui/js/Scripts.js +28 -0
  605. package/ui/js/Scroll.js +304 -0
  606. package/ui/js/ScrollOff.js +69 -0
  607. package/ui/js/Search.js +478 -0
  608. package/ui/js/Selection.js +97 -0
  609. package/ui/js/Settings.js +476 -0
  610. package/ui/js/SettingsAbout.js +97 -0
  611. package/ui/js/SettingsShelf.js +52 -0
  612. package/ui/js/SheetKeys.js +42 -0
  613. package/ui/js/SheetQuery.js +281 -0
  614. package/ui/js/ShelfPile.js +27 -0
  615. package/ui/js/SlowClick.js +53 -0
  616. package/ui/js/SlowOp.js +6 -0
  617. package/ui/js/Sort.js +134 -0
  618. package/ui/js/Startup.js +63 -0
  619. package/ui/js/StateWords.js +17 -0
  620. package/ui/js/Status.js +238 -0
  621. package/ui/js/Swap.js +166 -0
  622. package/ui/js/TabMove.js +39 -0
  623. package/ui/js/Tabs.js +751 -0
  624. package/ui/js/Tags.js +134 -0
  625. package/ui/js/Taildrop.js +128 -0
  626. package/ui/js/Tap.js +180 -0
  627. package/ui/js/TextSize.js +107 -0
  628. package/ui/js/Thumbs.js +158 -0
  629. package/ui/js/Transfer.js +172 -0
  630. package/ui/js/Trash.js +84 -0
  631. package/ui/js/TrashDates.js +47 -0
  632. package/ui/js/TrashDrop.js +64 -0
  633. package/ui/js/UiState.js +438 -0
  634. package/ui/js/Unlock.js +152 -0
  635. package/ui/js/Update.js +130 -0
  636. package/ui/js/UserDirs.js +56 -0
  637. package/ui/qmldir +230 -0
@@ -0,0 +1,308 @@
1
+ import QtQuick
2
+ import "." as Flea
3
+ import "js/Match.js" as Match
4
+ import "js/Picker.js" as Picker
5
+ import "js/Keymap.js" as Keymap
6
+ import "js/GridGeometry.js" as GridGeometry
7
+ import "js/Density.js" as Density
8
+ import "js/Thumbs.js" as Thumbs
9
+ import "js/ExtThumbs.js" as ExtThumbs
10
+ import "js/Sort.js" as Sort
11
+
12
+ // Issue #191 grid mode: the main window's tiles over the same rows, visible tiles only.
13
+ GridView {
14
+ id: root
15
+
16
+ property var picker: null
17
+ // The listing worker, which holds the rows a thumb request names; see ui/PickerListing.qml.
18
+ property var backend: null
19
+
20
+ // The first screen outlasts the compositor's resize, the fling debounce after that.
21
+ readonly property int firstSettleMs: 70
22
+ readonly property int settleMs: 120
23
+
24
+ // The same tile maths the main grid lays out by, so a tile here is a tile there.
25
+ readonly property int columns: GridGeometry.columnsFor(root.width, Theme.grid.minCellWidth,
26
+ ViewState.thumbnailPixels, Theme.spacing.rowPaddingX, Theme.spacing.gap, Theme.spacing.rowPaddingX)
27
+ readonly property int cellHeightPx: GridGeometry.cellHeightFor(ViewState.thumbnailPixels, Theme.spacing.gap,
28
+ Math.ceil(Theme.grid.captionHeight),
29
+ Density.gridPadY(Theme.spacing.rowPaddingX, ViewState.density))
30
+ readonly property int visibleTileRows: Math.max(1, Math.ceil(root.height / root.cellHeightPx))
31
+ onColumnsChanged: if (root.visible) settle.restart()
32
+ onVisibleTileRowsChanged: if (root.visible) settle.restart()
33
+
34
+ // Hidden builds nothing: a hidden view is not a free view, AGENTS.md rule 6.
35
+ model: root.visible ? root.picker.total : 0
36
+ clip: true
37
+ boundsBehavior: Flickable.StopAtBounds
38
+ highlightMoveDuration: 0
39
+ reuseItems: true
40
+ cacheBuffer: root.cellHeightPx * 2
41
+ activeFocusOnTab: true
42
+ Keys.onTabPressed: function(event) { root.picker.stepFocus(root, (event.modifiers & Qt.ShiftModifier) !== 0) }
43
+ Keys.onBacktabPressed: root.picker.stepFocus(root, true)
44
+ property bool firstArmed: false
45
+ // The previous tap path, so a rebuilt grid never sends a tile the first tap missed.
46
+ property string lastTapPath: ""
47
+ leftMargin: Theme.spacing.gap
48
+ topMargin: Theme.spacing.gap
49
+ cellWidth: GridGeometry.cellWidthFor(root.width, root.columns, Theme.spacing.gap, Theme.spacing.rowPaddingX)
50
+ cellHeight: root.cellHeightPx
51
+ Flea.FastScrollHandler { flickable: root }
52
+ Flea.ViewportScrollBar {
53
+ parent: root
54
+ anchors { top: parent.top; right: parent.right }
55
+ flickable: root
56
+ }
57
+
58
+ delegate: Item {
59
+ id: cell
60
+ required property int index
61
+ readonly property int listingIndex: index
62
+ readonly property var row: root.picker.rowFor(cell.listingIndex)
63
+ readonly property string rowPath: cell.row ? Picker.rowPath(root.picker.path, cell.row.n) : ""
64
+ // A Recent row is named by its whole path, drawn by its own leaf; see ui/PickerList.qml.
65
+ readonly property var shownRow: cell.row && root.picker.recent
66
+ ? Object.assign({}, cell.row, { n: Match.base(cell.row.n) })
67
+ : cell.row
68
+ // A file request marks files and a folder request marks folders; the other kind is a way
69
+ // through the tree and never an answer, so it carries no box at all.
70
+ readonly property bool markable: root.picker.marksAllowed && cell.row !== null && Picker.directory(cell.row) === root.picker.folderMode
71
+ readonly property bool isMarked: cell.markable && Picker.marked(root.picker.marks, cell.rowPath)
72
+
73
+ width: root.cellWidth
74
+ height: root.cellHeight
75
+
76
+ Flea.GridTile {
77
+ anchors.fill: parent
78
+ row: cell.shownRow
79
+ cursor: cell.listingIndex === root.picker.cursorIndex
80
+ hovered: hover.hovered
81
+ selected: cell.isMarked
82
+ thumb: root.thumbFor(cell.listingIndex)
83
+ }
84
+
85
+ // The board's box, one gap in from the tile's top left; the cursor tile's mark is
86
+ // foreground through GridTile itself, like the main grid.
87
+ Flea.PickerBox {
88
+ id: box
89
+ visible: cell.markable
90
+ x: Theme.spacing.gap
91
+ y: Theme.spacing.gap
92
+ marked: cell.isMarked
93
+ }
94
+
95
+ HoverHandler {
96
+ id: hover
97
+ }
98
+
99
+ TapHandler {
100
+ id: tap
101
+ acceptedButtons: Qt.LeftButton
102
+ // One tap moves the cursor; a same-path double tap opens, accepts or marks by mode; a box tap toggles.
103
+ onTapped: function (eventPoint, button) {
104
+ var was = root.picker.cursorIndex
105
+ var extending = (tap.point.modifiers & Qt.ShiftModifier) !== 0 && root.picker.marksAllowed
106
+ if (!extending) root.picker.endRange()
107
+ root.picker.cursorIndex = cell.listingIndex
108
+ root.forceActiveFocus()
109
+ var onBox = box.visible && eventPoint.position.x <= box.x + box.width + Theme.spacing.gap
110
+ && eventPoint.position.y <= box.y + box.height + Theme.spacing.gap
111
+ var second = tap.tapCount === 2
112
+ var firstPath = root.lastTapPath
113
+ root.lastTapPath = cell.rowPath
114
+ if (extending)
115
+ root.picker.markRange(was, cell.listingIndex)
116
+ else if (onBox)
117
+ root.picker.toggleMark(cell.listingIndex)
118
+ else if (second && Picker.sameTap(firstPath, cell.rowPath))
119
+ root.picker.doubleActivate(cell.listingIndex, cell.rowPath, firstPath)
120
+ }
121
+ }
122
+ }
123
+
124
+ // One tile row of bare ground at the end, the same inset the main grid keeps.
125
+ footer: Item {
126
+ width: Math.max(0, root.width - Theme.spacing.rowPaddingX)
127
+ height: Theme.chromeHeight
128
+ }
129
+
130
+ function moveCursor(delta, extending) {
131
+ if (root.picker.total === 0)
132
+ return
133
+ var to = Picker.gridTarget(root.picker.cursorIndex, delta, root.columns, root.picker.total)
134
+ var before = root.picker.cursorIndex
135
+ if (!extending) root.picker.endRange()
136
+ root.picker.cursorIndex = to
137
+ if (extending) root.picker.markRange(before, to)
138
+ root.positionViewAtIndex(to, GridView.Contain)
139
+ }
140
+
141
+ function jumpTo(index) {
142
+ if (root.picker.total === 0)
143
+ return
144
+ root.picker.endRange()
145
+ var to = Math.max(0, Math.min(root.picker.total - 1, index))
146
+ root.picker.cursorIndex = to
147
+ root.positionViewAtIndex(to, GridView.Contain)
148
+ }
149
+
150
+ function thumbFor(index) {
151
+ return Thumbs.allowed(root.picker.rowFor(index), ViewState.thumbnailMode)
152
+ ? Thumbs.fileFor(root.picker.thumbState, index) : ""
153
+ }
154
+
155
+ // One dispatch for every action the lookup names, so a key test pins the live path.
156
+ function handleAction(action, key, modifiers) {
157
+ if (action === "pathBar") {
158
+ root.firstArmed = false
159
+ root.picker.openPathBar()
160
+ return true
161
+ }
162
+ if (action === "cursorFirstArm") {
163
+ if (root.firstArmed) root.jumpTo(0)
164
+ root.firstArmed = !root.firstArmed
165
+ return true
166
+ }
167
+ root.firstArmed = false
168
+ if (key === Qt.Key_Escape) {
169
+ root.picker.cancel()
170
+ } else if (action === "cursorDown") {
171
+ root.moveCursor(root.columns)
172
+ } else if (action === "cursorUp") {
173
+ root.moveCursor(-root.columns)
174
+ } else if (action === "extendDown") {
175
+ root.moveCursor(root.columns, true)
176
+ } else if (action === "extendUp") {
177
+ root.moveCursor(-root.columns, true)
178
+ } else if (action === "selectAll") {
179
+ root.picker.selectAll()
180
+ } else if (action === "pageDown") {
181
+ root.jumpTo(Picker.pageTarget(root.picker.cursorIndex, root.visibleTileRows * root.columns, root.picker.total))
182
+ } else if (action === "pageUp") {
183
+ root.jumpTo(Picker.pageTarget(root.picker.cursorIndex, -root.visibleTileRows * root.columns, root.picker.total))
184
+ } else if (action === "cursorFirst") {
185
+ root.jumpTo(0)
186
+ } else if (action === "cursorLast") {
187
+ root.jumpTo(root.picker.total - 1)
188
+ } else if (action === "viewList") {
189
+ root.picker.setView("list")
190
+ } else if (action === "viewGrid") {
191
+ root.picker.setView("grid")
192
+ } else if (key === Qt.Key_Space && modifiers === Qt.NoModifier) {
193
+ root.picker.toggleMark(root.picker.cursorIndex)
194
+ } else if (Picker.activates(action, key)) {
195
+ root.picker.activate(root.picker.cursorIndex)
196
+ } else if (action === "parent") {
197
+ root.picker.goUp()
198
+ } else if (action === "historyBack") {
199
+ root.picker.goBack()
200
+ } else if (action === "sortNext") {
201
+ root.picker.requestSort(Sort.nextOrder(Picker.SORT_ORDERS, root.picker.sortBy))
202
+ } else if (action === "sortReverse") {
203
+ root.picker.requestSort(Sort.reverseOrder(root.picker.sortBy, root.picker.sortDesc))
204
+ } else if (action === "toggleHidden") {
205
+ root.picker.showHidden = !root.picker.showHidden
206
+ if (root.picker.path.length > 0)
207
+ root.picker.openWithoutHistory(root.picker.path)
208
+ } else {
209
+ return false
210
+ }
211
+ return true
212
+ }
213
+
214
+ Keys.onPressed: function (event) {
215
+ // Bare arrows and h/l step to visual neighbours in the grid, the main grid's own rule;
216
+ // the map below would read them as parent and browse-in instead.
217
+ if (event.modifiers === Qt.NoModifier
218
+ && (event.key === Qt.Key_Left || event.key === Qt.Key_Right
219
+ || event.text === "h" || event.text === "l")) {
220
+ var across = (event.key === Qt.Key_Left || event.text === "h") ? -1 : 1
221
+ event.accepted = true
222
+ root.firstArmed = false
223
+ root.moveCursor(across)
224
+ return
225
+ }
226
+ var action = Keymap.lookup(event.key, event.text, event.modifiers, "listing")
227
+ event.accepted = root.handleAction(action, event.key, event.modifiers)
228
+ }
229
+
230
+ // A scroll refetches the window and restarts the thumb settle for newly visible tiles.
231
+ // Held rows are never refetched, so without the restart no settle asks for them.
232
+ onContentYChanged: {
233
+ coalesce.restart()
234
+ settle.restart()
235
+ }
236
+
237
+ Timer {
238
+ id: coalesce
239
+ interval: root.picker.coalesceMs
240
+ onTriggered: root.requestIfDrifted()
241
+ }
242
+
243
+ // Settle fires counted, so a probe waits on the first run rather than a delay.
244
+ property int settleRuns: 0
245
+ // Whether a settle fire is pending, so a probe quiesces before proving a restart.
246
+ property alias settleRunning: settle.running
247
+ Timer {
248
+ id: settle
249
+ interval: root.firstSettleMs
250
+ onTriggered: { root.settleRuns += 1; root.requestThumbs() }
251
+ }
252
+
253
+ function primeSettle() { settle.interval = root.firstSettleMs }
254
+ function restartSettle() { settle.restart() }
255
+
256
+ // A reshow owns its window: move to the cursor, refetch there, restart thumbs.
257
+ function reshow(index) {
258
+ root.positionViewAtIndex(index, GridView.Contain)
259
+ root.requestIfDrifted()
260
+ root.restartSettle()
261
+ }
262
+
263
+ function requestIfDrifted() {
264
+ if (!root.visible || root.picker.backendUnavailable || root.picker.total === 0 || root.picker.pendingListings > 0)
265
+ return
266
+ var range = Picker.tileRange(root.contentY, root.cellHeightPx, root.visibleTileRows, root.columns, root.picker.total)
267
+ var heldEnd = root.picker.held + root.picker.rows.length
268
+ if (root.picker.rows.length === 0
269
+ || (range.first < root.picker.held && root.picker.held > 0)
270
+ || (range.last >= heldEnd && heldEnd < root.picker.total)) {
271
+ var start = Math.max(0, range.first - Math.floor(root.picker.windowSize * root.picker.windowLead))
272
+ root.backend.window(Math.floor(start), root.picker.windowSize)
273
+ }
274
+ }
275
+
276
+ // Only the visible tiles, only once each, and only after the grid has stopped moving.
277
+ // Unknown storage holds until fsinfo names it, so the first screen never decodes as local.
278
+ function requestThumbs() {
279
+ if (!root.visible || root.picker.backendUnavailable || root.picker.total === 0
280
+ || root.picker.pendingListings > 0 || root.picker.recent || !root.picker.storageKnown)
281
+ return
282
+ var range = Picker.tileRange(root.contentY, root.cellHeightPx, root.visibleTileRows, root.columns, root.picker.total)
283
+ var work = Thumbs.plan(root.picker.thumbState, root.picker.rows, root.picker.held,
284
+ range.first, range.last, ViewState.thumbnailMode)
285
+ root.backend.thumbcancel(work.drop)
286
+ // An off class still asks; the worker answers from the cache alone, see ui/js/ExtThumbs.js.
287
+ work.cacheOnly = ExtThumbs.cacheOnly(root.picker.storageClass, ViewState.preview)
288
+ root.backend.thumb(work.ask, work.cacheOnly)
289
+ if (work.ask.length > 0)
290
+ settle.interval = root.settleMs
291
+ root.thumbsApplied(work)
292
+ }
293
+
294
+ signal thumbsApplied(var work)
295
+
296
+ Connections {
297
+ target: root.picker
298
+ function onRowsChanged() { if (root.visible) settle.restart() }
299
+ function onTotalChanged() { if (root.visible) { root.primeSettle(); settle.restart() } }
300
+ }
301
+
302
+ Connections {
303
+ target: ViewState
304
+ function onThumbnailModeChanged() { if (root.visible) settle.restart() }
305
+ function onThumbnailPixelsChanged() { if (root.visible) settle.restart() }
306
+ function onPreviewChanged() { if (root.visible) settle.restart() }
307
+ }
308
+ }
@@ -0,0 +1,28 @@
1
+ import QtQuick
2
+ import "." as Flea
3
+ import "js/Picker.js" as Picker
4
+ import "js/Sort.js" as Sort
5
+
6
+ // Owns no sort state; the picker's sortable gates both this click and the s and S keys so they cannot differ.
7
+ Flea.Header {
8
+ id: root
9
+ required property var picker
10
+ required property var backend
11
+
12
+ hiddenCols: Picker.HIDDEN_COLS
13
+ compactDate: true
14
+ enabled: root.picker.sortable
15
+ // Recent is the desktop's own order, so no mark; the mark moves on the click, not the reply.
16
+ sortBy: root.picker.recent ? "" : root.backend.sortBy
17
+ sortDesc: root.backend.sortDesc
18
+ onSortRequested: function (key) {
19
+ root.picker.requestSort(Sort.columnOrder(Picker.SORT_ORDERS, root.backend.sortBy, root.backend.sortDesc, key))
20
+ }
21
+
22
+ // What tests/picker-native.py clicks, in the shape every other chooser control reports.
23
+ function controls() {
24
+ return [["Sort by Name", "name"], ["Sort by Size", "size"], ["Sort by Modified", "date"]].map(function (entry) {
25
+ return root.picker.control(entry[0], root.cell(entry[1]), root.enabled)
26
+ })
27
+ }
28
+ }
@@ -0,0 +1,27 @@
1
+ import QtQuick
2
+
3
+ // Called only after the portal reply has been saved (or the save has failed). Both processes are
4
+ // owned by this chooser; neither can write selected files, so a stalled read needs no write drain.
5
+ Item {
6
+ id: root
7
+ required property var checks
8
+ required property var listing
9
+ signal stopped()
10
+ property bool checksStopped: false
11
+ property bool listingStopped: false
12
+ property bool finished: false
13
+ function quit() { listing.quit(); checks.quit() }
14
+ function finish() {
15
+ if (finished || !checksStopped || !listingStopped) return
16
+ finished = true
17
+ stopped()
18
+ }
19
+ Connections {
20
+ target: root.checks
21
+ function onQuitReady() { root.checksStopped = true; root.finish() }
22
+ }
23
+ Connections {
24
+ target: root.listing
25
+ function onQuitReady() { root.listingStopped = true; root.finish() }
26
+ }
27
+ }
@@ -0,0 +1,218 @@
1
+ import QtQuick
2
+ import qs.Commons
3
+ import "." as Flea
4
+ import "js/Match.js" as Match
5
+ import "js/Picker.js" as Picker
6
+ import "js/Keymap.js" as Keymap
7
+ import "js/MarkBox.js" as MarkBox
8
+ import "js/Scroll.js" as Scroll
9
+ import "js/Sort.js" as Sort
10
+
11
+ // The picker's listing: ui/Row.qml drawn behind a check box, and the keys that move through it. The
12
+ // window's own ui/List.qml is not reused, because every line of it that is not layout is a drag, a
13
+ // rename, a thumbnail or a context menu, and a chooser has none of those.
14
+ ListView {
15
+ id: root
16
+
17
+ property var picker: null
18
+ property var backend: null
19
+
20
+ readonly property int visibleRows: Math.max(1, Math.ceil(root.height / Theme.rowHeight))
21
+ // PickerBox's outer size, read by the header's leading slot.
22
+ readonly property int checkSize: MarkBox.outer(Theme.font.bodySmall, Theme.spacing.hairline)
23
+
24
+ // Hidden builds nothing: a hidden view is not a free view, AGENTS.md rule 6.
25
+ model: root.visible ? root.picker.shownTotal : 0
26
+ clip: true
27
+ boundsBehavior: Flickable.StopAtBounds
28
+ highlightMoveDuration: 0
29
+ reuseItems: true
30
+ cacheBuffer: Theme.rowHeight * 4
31
+ activeFocusOnTab: true
32
+ Keys.onTabPressed: function(event) { root.picker.stepFocus(root, (event.modifiers & Qt.ShiftModifier) !== 0) }
33
+ Keys.onBacktabPressed: root.picker.stepFocus(root, true)
34
+ property bool firstArmed: false
35
+ // The previous tap path, so a rebuilt list never sends a row the first tap missed.
36
+ property string lastTapPath: ""
37
+ Flea.FastScrollHandler { flickable: root }
38
+ Flea.ViewportScrollBar {
39
+ parent: root
40
+ anchors { top: parent.top; right: parent.right }
41
+ flickable: root
42
+ }
43
+
44
+ delegate: Item {
45
+ id: cell
46
+ required property int index
47
+ readonly property int listingIndex: index
48
+ readonly property var row: root.picker.rowFor(cell.listingIndex)
49
+ readonly property string rowPath: cell.row ? Picker.rowPath(root.picker.path, cell.row.n) : ""
50
+ // A Recent row is named by its whole path under the listing base, and SendPicker.html draws
51
+ // the file's own name; the row handed to Row.qml is the same row under that name.
52
+ readonly property var shownRow: cell.row && root.picker.recent
53
+ ? Object.assign({}, cell.row, { n: Match.base(cell.row.n) })
54
+ : cell.row
55
+ // A file request marks files and a folder request marks folders; the other kind is a way
56
+ // through the tree and never an answer, so it carries no box at all.
57
+ readonly property bool markable: root.picker.marksAllowed && cell.row !== null && Picker.directory(cell.row) === root.picker.folderMode
58
+ readonly property bool isMarked: cell.markable && Picker.marked(root.picker.marks, cell.rowPath)
59
+
60
+ // The scroll lane stays clear, the same rule the window's own list follows.
61
+ width: Scroll.contentWidth(root.width, Theme.spacing.rowPaddingX)
62
+ height: Theme.rowHeight
63
+
64
+ // The board's marked row: the selection fill under the row's own text, never folded with the cursor rung ui/Row.qml paints.
65
+ Rectangle {
66
+ visible: cell.isMarked
67
+ width: root.width
68
+ height: parent.height
69
+ color: Style.selectionFill
70
+ }
71
+
72
+ Flea.Row {
73
+ anchors.fill: parent
74
+ paintWidth: root.width
75
+ leadingSlot: root.picker.marksAllowed ? root.checkSize + Theme.spacing.gap : 0
76
+ compactDate: true
77
+ foregroundMetadata: true
78
+ hiddenCols: Picker.HIDDEN_COLS
79
+ row: cell.shownRow
80
+ cursor: cell.listingIndex === root.picker.cursorIndex
81
+ hovered: hover.hovered
82
+ kindNames: root.picker.kindNames
83
+ }
84
+
85
+ Flea.PickerBox {
86
+ id: box
87
+ visible: cell.markable
88
+ anchors.left: parent.left
89
+ anchors.leftMargin: Theme.spacing.rowPaddingX
90
+ anchors.verticalCenter: parent.verticalCenter
91
+ marked: cell.isMarked
92
+ }
93
+
94
+ HoverHandler {
95
+ id: hover
96
+ }
97
+
98
+ TapHandler {
99
+ id: tap
100
+ acceptedButtons: Qt.LeftButton
101
+ // One tap moves the cursor; a same-path double tap opens, accepts or marks by mode; a box tap toggles.
102
+ onTapped: function (eventPoint, button) {
103
+ var was = root.picker.cursorIndex
104
+ var extending = (tap.point.modifiers & Qt.ShiftModifier) !== 0 && root.picker.marksAllowed
105
+ if (!extending) root.picker.endRange()
106
+ root.picker.cursorIndex = cell.listingIndex
107
+ root.forceActiveFocus()
108
+ var onBox = box.visible && eventPoint.position.x <= box.x + box.width + Theme.spacing.gap
109
+ var second = tap.tapCount === 2
110
+ var firstPath = root.lastTapPath
111
+ root.lastTapPath = cell.rowPath
112
+ if (extending)
113
+ root.picker.markRange(was, cell.listingIndex)
114
+ else if (onBox)
115
+ root.picker.toggleMark(cell.listingIndex)
116
+ else if (second && Picker.sameTap(firstPath, cell.rowPath))
117
+ root.picker.doubleActivate(cell.listingIndex, cell.rowPath, firstPath)
118
+ }
119
+ }
120
+ }
121
+
122
+ function moveCursor(delta, extending) {
123
+ if (root.picker.shownTotal === 0)
124
+ return
125
+ var was = root.picker.cursorIndex
126
+ var to = Math.max(0, Math.min(root.picker.shownTotal - 1, was + delta))
127
+ if (!extending) root.picker.endRange()
128
+ root.picker.cursorIndex = to
129
+ if (extending) root.picker.markRange(was, to)
130
+ root.positionViewAtIndex(to, ListView.Contain)
131
+ }
132
+
133
+ Keys.onPressed: function (event) {
134
+ var action = Keymap.lookup(event.key, event.text, event.modifiers, "listing")
135
+ event.accepted = true
136
+ if (action === "cursorFirstArm") {
137
+ if (root.firstArmed) root.moveCursor(-root.picker.shownTotal)
138
+ root.firstArmed = !root.firstArmed
139
+ return
140
+ }
141
+ root.firstArmed = false
142
+ if (event.key === Qt.Key_Escape) {
143
+ root.picker.cancel()
144
+ } else if (action === "cursorDown") {
145
+ root.moveCursor(1)
146
+ } else if (action === "cursorUp") {
147
+ root.moveCursor(-1)
148
+ } else if (action === "extendDown") {
149
+ root.moveCursor(1, true)
150
+ } else if (action === "extendUp") {
151
+ root.moveCursor(-1, true)
152
+ } else if (action === "selectAll") {
153
+ root.picker.selectAll()
154
+ } else if (action === "pageDown") {
155
+ root.moveCursor(root.visibleRows)
156
+ } else if (action === "pageUp") {
157
+ root.moveCursor(-root.visibleRows)
158
+ } else if (action === "cursorFirst") {
159
+ root.moveCursor(-root.picker.shownTotal)
160
+ } else if (action === "cursorLast") {
161
+ root.moveCursor(root.picker.shownTotal)
162
+ } else if (action === "viewList") {
163
+ root.picker.setView("list")
164
+ } else if (action === "viewGrid") {
165
+ root.picker.setView("grid")
166
+ } else if (event.key === Qt.Key_Space && event.modifiers === Qt.NoModifier) {
167
+ root.picker.toggleMark(root.picker.cursorIndex)
168
+ } else if (Picker.activates(action, event.key)) {
169
+ root.picker.activate(root.picker.cursorIndex)
170
+ } else if (action === "parent") {
171
+ root.picker.goUp()
172
+ } else if (action === "historyBack") {
173
+ root.picker.goBack()
174
+ } else if (action === "sortNext") {
175
+ root.picker.requestSort(Sort.nextOrder(Picker.SORT_ORDERS, root.picker.sortBy))
176
+ } else if (action === "sortReverse") {
177
+ root.picker.requestSort(Sort.reverseOrder(root.picker.sortBy, root.picker.sortDesc))
178
+ } else if (action === "toggleHidden") {
179
+ root.picker.showHidden = !root.picker.showHidden
180
+ if (root.picker.path.length > 0)
181
+ root.picker.openWithoutHistory(root.picker.path)
182
+ } else if (action === "pathBar") {
183
+ root.firstArmed = false
184
+ root.picker.openPathBar()
185
+ } else {
186
+ event.accepted = false
187
+ }
188
+ }
189
+
190
+ // The listing is a window around the viewport, not the directory, so scrolling refetches. Same
191
+ // shape as ui/List.qml's own drift check, minus the thumbnail and directory-size planners.
192
+ onContentYChanged: coalesce.restart()
193
+
194
+ Timer {
195
+ id: coalesce
196
+ interval: root.picker.coalesceMs
197
+ onTriggered: root.requestIfDrifted()
198
+ }
199
+
200
+ function requestIfDrifted() {
201
+ if (!root.visible || root.picker.backendUnavailable || root.picker.total === 0 || root.picker.pendingListings > 0)
202
+ return
203
+ var firstVisible = Math.floor(root.contentY / Theme.rowHeight)
204
+ var heldEnd = root.picker.held + root.picker.rows.length
205
+ if (root.picker.rows.length === 0
206
+ || (firstVisible < root.picker.held && root.picker.held > 0)
207
+ || (firstVisible + root.visibleRows > heldEnd && heldEnd < root.picker.total)) {
208
+ var start = Math.max(0, firstVisible - Math.floor(root.picker.windowSize * root.picker.windowLead))
209
+ root.backend.window(Math.floor(start), root.picker.windowSize)
210
+ }
211
+ }
212
+
213
+ // A reshow owns its window: move to the cursor and refetch there.
214
+ function reshow(index) {
215
+ root.positionViewAtIndex(index, ListView.Contain)
216
+ root.requestIfDrifted()
217
+ }
218
+ }