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,492 @@
1
+ import QtQuick
2
+ import Quickshell
3
+ import qs.Commons
4
+ import "." as Flea
5
+ import "js/Format.js" as Format
6
+ import "js/Icons.js" as Icons
7
+ import "js/Keymap.js" as Keymap
8
+ import "js/Ops.js" as Ops
9
+ import "js/Sort.js" as Sort
10
+ import "js/Tap.js" as Tap
11
+ import "js/TrashDates.js" as Trash
12
+ import "js/Trash.js" as TrashKeys
13
+
14
+ // Trash keeps the normal integer ListView model, holding metadata only for its current window.
15
+ FocusScope {
16
+ id: root
17
+ property bool opened: false
18
+ property Item overlayParent: null
19
+ property var railKeyHandler: null
20
+ property var statusBar: null
21
+ property int total: 0
22
+ property real totalBytes: 0
23
+ property bool bytesReady: false
24
+ property bool bytesPartial: false
25
+ property int first: 0
26
+ property var rows: []
27
+ property var selected: ({})
28
+ property var selectionIdentities: ({})
29
+ property bool allSelected: false
30
+ property int selectionToken: 0
31
+ property int selectionCount: 0
32
+ property int cursor: 0
33
+ property double trashArmedAt: 0
34
+ property int requestId: 0
35
+ property string pendingOp: ""
36
+ property bool operationActive: false
37
+ readonly property bool busy: pendingOp.length > 0
38
+ property bool refreshPending: false
39
+ property bool confirming: false
40
+ property string initialAction: ""
41
+ property int pendingSelection: -1
42
+ // The first list after open() puts the cursor, and its mark, on the newest row.
43
+ property bool landing: false
44
+ property var pendingExtend: false
45
+ property string errorText: ""
46
+ property bool confirmingAll: false
47
+ property var confirmingUris: []
48
+ property var confirmingExcluded: []
49
+ property bool confirmingSelectionAll: false
50
+ property int confirmingSelectionToken: 0
51
+ property var confirmingIdentities: []
52
+ property int confirmingToken: 0
53
+ // The sentence a recovered journal answers with, one whole sentence per count, each filled by Format.fill.
54
+ readonly property var recoveredWords: ({ one: "Recovered 1 interrupted file operation", many: "Recovered %1 interrupted file operations" })
55
+ readonly property bool confirmationOpen: confirmation.opened
56
+ readonly property var confirmationItem: confirmation
57
+ readonly property var backItem: backButton
58
+ readonly property var upItem: upButton
59
+ readonly property var emptyItem: emptyAction
60
+ readonly property var stripItem: strip
61
+ readonly property string countText: countLabel.text
62
+ readonly property var headerLabels: [nameTitle.text, locationTitle.text, "Deleted"]
63
+ function rowItemFor(index) { return listing.itemAtIndex(index) }
64
+ readonly property int windowRows: Math.max(1, Math.min(350, Math.ceil(listing.height / Theme.fileRowHeight) + 2))
65
+ readonly property int selectedCount: allSelected ? Math.max(0, selectionCount - excludedUris().length) + selectedUris().length : selectedUris().length
66
+ readonly property string home: Quickshell.env("HOME") || ""
67
+ signal requested(var message)
68
+ signal backRequested()
69
+ signal focusRailRequested()
70
+ signal actionRequested(string action)
71
+ signal contextRequested(real x, real y, bool hasSelection)
72
+ signal statusReported(string message, bool error)
73
+ // The dd prompt, said apart from a status line so the bar starts its arm from the signal and never by reading the sentence.
74
+ signal armReported(string text)
75
+ signal operationResult(string headline, string detail, bool error)
76
+ signal countChanged(int count)
77
+ anchors.fill: parent
78
+ visible: opened
79
+ onActiveFocusChanged: if (!activeFocus) root.trashArmedAt = 0
80
+ function send(op, fields) {
81
+ var message = fields || {}
82
+ message.c = "trashbrowse"
83
+ message.op = op
84
+ message.id = ++requestId
85
+ pendingOp = op
86
+ if (op === "restore" || op === "delete") operationActive = true
87
+ requested(message)
88
+ }
89
+ function open(action) {
90
+ trashArmedAt = 0
91
+ if (operationActive) { opened = true; emptyAction.focus = false; forceActiveFocus(); return }
92
+ opened = true; selected = ({}); selectionIdentities = ({}); allSelected = false; selectionToken = 0; selectionCount = 0; cursor = 0
93
+ first = 0; rows = []; total = 0; errorText = ""; bytesReady = false; landing = true
94
+ confirming = false; confirmation.close(); refreshPending = false
95
+ initialAction = action || ""
96
+ send("list", {start: 0, count: windowRows, recover: true})
97
+ emptyAction.focus = false; forceActiveFocus() // Fresh open never keeps the strip button.
98
+ }
99
+ function close() {
100
+ trashArmedAt = 0
101
+ opened = false; confirming = false; confirmation.close(); initialAction = ""
102
+ if (!operationActive) send("cancel", {clearSelection: true})
103
+ backRequested()
104
+ }
105
+ function refresh() {
106
+ if (!opened) return
107
+ if (busy) { refreshPending = true; return }
108
+ if (confirming) { sourceChanged(); return }
109
+ refreshPending = false
110
+ bytesReady = false
111
+ send("list", {start: first, count: windowRows, uris: Object.keys(selected)})
112
+ }
113
+ function sourceChanged() {
114
+ if (!opened) return
115
+ trashArmedAt = 0
116
+ if (confirmation.opened) confirmation.close()
117
+ if (busy) { refreshPending = true; return }
118
+ refreshPending = false
119
+ if (confirming) send("prepare", {all: confirmingSelectionAll, emptyTrash: confirmingAll, uris: confirmingUris, exclude: confirmingExcluded, identities: confirmingIdentities, selectionToken: confirmingSelectionToken, refreshToken: confirmingToken})
120
+ else refresh()
121
+ }
122
+ function ensureWindow() {
123
+ if (!opened || total === 0 || busy || confirmation.opened) return
124
+ var top = Math.max(0, Math.floor((listing.contentY - listing.originY) / Theme.fileRowHeight))
125
+ var end = Math.min(total, top + Math.ceil(listing.height / Theme.fileRowHeight))
126
+ if (top < first || end > first + rows.length)
127
+ send("window", {start: top, count: windowRows})
128
+ }
129
+ function rowAt(index) { return rows[index - first] || null }
130
+ function selectedUris() { return Object.keys(selected).filter(function(uri) { return selected[uri] }) }
131
+ function excludedUris() { return Object.keys(selected).filter(function(uri) { return selected[uri] === false }) }
132
+ function isSelected(uri) {
133
+ if (selected[uri] !== undefined) return selected[uri] === true
134
+ if (!allSelected) return false
135
+ for (var i = 0; i < rows.length; i++) if (rows[i].uri === uri) return rows[i].bulkSelected === true
136
+ return false
137
+ }
138
+ function selectAll() {
139
+ if (operationActive || confirming || pendingOp === "select" || total === 0) return
140
+ allSelected = false; selectionToken = 0; selectionCount = 0
141
+ selected = ({}); selectionIdentities = ({})
142
+ send("select")
143
+ }
144
+ function choose(index, extend) {
145
+ trashArmedAt = 0
146
+ if (total === 0 || confirming || operationActive) return
147
+ if (pendingOp === "select") send("cancel", {clearSelection: true})
148
+ cursor = Math.max(0, Math.min(total - 1, index))
149
+ listing.positionViewAtIndex(cursor, ListView.Contain)
150
+ var item = rowAt(cursor)
151
+ if (!item) {
152
+ pendingSelection = cursor; pendingExtend = extend
153
+ ensureWindow(); return
154
+ }
155
+ pendingSelection = -1
156
+ var next = extend ? Object.assign({}, selected) : ({})
157
+ var identities = extend ? Object.assign({}, selectionIdentities) : ({})
158
+ next[item.uri] = extend === "add" ? true : extend ? !isSelected(item.uri) : true
159
+ if (next[item.uri]) identities[item.uri] = item.identity
160
+ else delete identities[item.uri]
161
+ if (allSelected && extend && next[item.uri] && item.bulkSelected) {
162
+ delete next[item.uri]
163
+ delete identities[item.uri]
164
+ }
165
+ if (!extend) { allSelected = false; selectionToken = 0; selectionCount = 0 }
166
+ selected = next
167
+ selectionIdentities = identities
168
+ forceActiveFocus()
169
+ }
170
+ function extendSelection(direction) {
171
+ var previous = cursor
172
+ choose(previous, "add")
173
+ choose(previous + direction, "add")
174
+ }
175
+ function restore(all) {
176
+ if (busy || (all ? total === 0 : selectedCount === 0)) return
177
+ confirming = false
178
+ var uris = selectedUris()
179
+ send("restore", {all: all, selectionToken: !all && allSelected ? selectionToken : 0, uris: uris, exclude: all ? [] : excludedUris(), identities: uris.map(function(uri) { return root.selectionIdentities[uri] || "" })})
180
+ }
181
+ function prepare(all) {
182
+ if (busy || (all ? total === 0 : selectedCount === 0)) return
183
+ confirming = true
184
+ confirmingToken = 0
185
+ confirmingAll = all
186
+ confirmingSelectionAll = all
187
+ confirmingSelectionToken = !all && allSelected ? selectionToken : 0
188
+ confirmingUris = selectedUris()
189
+ confirmingExcluded = all ? [] : excludedUris()
190
+ confirmingIdentities = confirmingUris.map(function(uri) { return root.selectionIdentities[uri] || "" })
191
+ send("prepare", {all: confirmingSelectionAll, emptyTrash: all, uris: confirmingUris, exclude: confirmingExcluded, identities: confirmingIdentities, selectionToken: confirmingSelectionToken})
192
+ }
193
+ function armDelete() {
194
+ if (selectedCount === 0 || busy || confirming) { trashArmedAt = 0; return }
195
+ var now = Date.now()
196
+ var paired = trashArmedAt > 0 && now - trashArmedAt < TrashKeys.ARM_MS
197
+ trashArmedAt = paired ? 0 : now
198
+ if (paired) prepare(false)
199
+ else armReported(TrashKeys.reviewPrompt())
200
+ }
201
+ function receive(message) {
202
+ if ((!opened && !operationActive) || message.id !== requestId || message.op !== pendingOp) return
203
+ pendingOp = ""
204
+ if (!message.ok) {
205
+ if (message.stale && opened) { operationActive = false; confirming = true; sourceChanged(); return }
206
+ errorText = message.error || "That Trash action could not be completed."
207
+ confirming = false; confirmation.close()
208
+ statusReported(errorText, true)
209
+ operationActive = false
210
+ return
211
+ }
212
+ if (message.op === "list" || message.op === "window") {
213
+ total = message.total
214
+ countChanged(total)
215
+ first = message.start
216
+ rows = message.rows || []
217
+ if (allSelected) {
218
+ selectionCount = message.selectionCount || 0
219
+ if (message.selectionStale || message.selectionToken !== selectionToken) {
220
+ allSelected = false; selectionToken = 0; selectionCount = 0
221
+ selected = ({}); selectionIdentities = ({})
222
+ statusReported("Trash selection changed; select the items again.", true)
223
+ }
224
+ }
225
+ cursor = Math.max(0, Math.min(cursor, total - 1))
226
+ if (message.op === "list") {
227
+ if ((message.recoveryErrors || []).length > 0)
228
+ operationResult("Flea could not finish an interrupted file action", message.recoveryErrors.join("\n"), true)
229
+ else if (message.recoveredCount > 0)
230
+ operationResult(message.recoveredCount === 1 ? root.recoveredWords.one : Format.fill(root.recoveredWords.many, message.recoveredCount), "", false)
231
+ errorText = ""
232
+ var kept = ({})
233
+ var keptIdentities = ({})
234
+ var present = message.present || []
235
+ for (var p = 0; p < present.length; p++) {
236
+ kept[present[p]] = selected[present[p]]
237
+ if (selectionIdentities[present[p]]) keptIdentities[present[p]] = selectionIdentities[present[p]]
238
+ }
239
+ selected = kept
240
+ selectionIdentities = keptIdentities
241
+ if (total === 0) allSelected = false
242
+ var action = initialAction; initialAction = ""
243
+ if (action === "emptyTrash") prepare(true)
244
+ else if (action === "restoreAll") restore(true)
245
+ else { if (landing && total > 0) choose(0, false); send("summary") }
246
+ landing = false
247
+ }
248
+ if (pendingSelection >= 0 && rowAt(pendingSelection)) choose(pendingSelection, pendingExtend)
249
+ } else if (message.op === "select") {
250
+ selectionToken = message.selectionToken || 0
251
+ selectionCount = message.selectionCount || 0
252
+ allSelected = selectionToken > 0
253
+ send("window", {start: first, count: windowRows})
254
+ } else if (message.op === "summary") {
255
+ totalBytes = message.bytes
256
+ bytesPartial = message.partial
257
+ bytesReady = true
258
+ } else if (message.op === "prepare" && confirming) {
259
+ confirmingToken = message.token
260
+ if (!refreshPending) confirmation.open(message)
261
+ }
262
+ else if (message.op === "check" && !message.valid) {
263
+ sourceChanged()
264
+ } else if (message.op === "cancel") {
265
+ refresh()
266
+ } else if (message.op === "restore" || message.op === "delete") {
267
+ var failed = message.failed || 0
268
+ var next = ({})
269
+ var failures = message.failures || []
270
+ var identities = ({})
271
+ for (var i = 0; i < failures.length; i++) {
272
+ next[failures[i].uri] = true
273
+ if (failures[i].identity) identities[failures[i].uri] = failures[i].identity
274
+ }
275
+ selectionIdentities = identities
276
+ allSelected = false; selectionToken = 0; selectionCount = 0; selected = next
277
+ var text = Ops.doneOf(message.op === "restore" ? "Restored" : "Deleted", message.done, message.done + failed)
278
+ if (failed) text += " · " + Format.count(failed) + " failed"
279
+ var detail = failures.map(function(item) { return (item.name || item.uri) + " failed: " + item.error }).join("\n")
280
+ operationResult(text, detail, failed > 0)
281
+ refresh()
282
+ operationActive = false
283
+ }
284
+ if (refreshPending && !busy) sourceChanged()
285
+ else if (!busy) ensureWindow()
286
+ }
287
+ Keys.onPressed: function(event) {
288
+ if (root.railKeyHandler && root.railKeyHandler(event)) { event.accepted = true; return }
289
+ var action = Keymap.lookup(event.key, event.text, event.modifiers, "listing", "gui")
290
+ if (action === "trashArm" && event.isAutoRepeat) { event.accepted = true; return }
291
+ if (action !== "trashArm") root.trashArmedAt = 0
292
+ var unmodified = (event.modifiers & (Qt.ControlModifier | Qt.ShiftModifier | Qt.AltModifier | Qt.MetaModifier)) === 0
293
+ if (action === "escape" && root.statusBar && root.statusBar.escapePressed()) { event.accepted = true; return }
294
+ if (action === "escape" || (event.key === Qt.Key_Backspace && unmodified)) root.close()
295
+ else if (action === "cursorDown") root.choose(root.cursor + 1, false)
296
+ else if (action === "cursorUp") root.choose(root.cursor - 1, false)
297
+ else if (action === "cursorFirst") root.choose(0, false)
298
+ else if (action === "cursorLast") root.choose(root.total - 1, false)
299
+ else if (action === "pageDown" || action === "pageUp") root.choose(root.cursor + (action === "pageDown" ? 1 : -1) * Math.max(1, root.windowRows - 2), false)
300
+ else if (action === "toggleSelect") root.choose(root.cursor, true)
301
+ else if (action === "extendDown" || action === "extendUp") root.extendSelection(action === "extendDown" ? 1 : -1)
302
+ else if (action === "selectAll") root.selectAll()
303
+ else if (action === "trashArm") root.armDelete()
304
+ else if (action === "deletePermanently" || action === "trash") root.prepare(false)
305
+ else if (action === "focusNext") root.focusRailRequested()
306
+ else if (action === "quit" || TrashKeys.route(action) !== "trash") root.actionRequested(action)
307
+ else if (action === "reload" || event.key === Qt.Key_F5 && unmodified) root.refresh()
308
+ else if (action === "menu") root.openMenu()
309
+ // Trash owns this focus context; ordinary filesystem actions must never reach the covered pane.
310
+ event.accepted = true
311
+ }
312
+ Rectangle { anchors.fill: parent; color: Theme.color.background }
313
+ Column {
314
+ anchors.fill: parent
315
+ spacing: 0
316
+ Rectangle {
317
+ id: strip
318
+ width: parent.width
319
+ height: Theme.chromeHeight
320
+ color: Theme.color.surface
321
+ Row {
322
+ anchors.fill: parent
323
+ anchors.leftMargin: Theme.spacing.rowPaddingX
324
+ anchors.rightMargin: Theme.spacing.rowPaddingX
325
+ spacing: Theme.spacing.gap
326
+ Flea.ChromeButton {
327
+ id: backButton
328
+ ruleRows: Theme.spacing.hairline
329
+ glyph: "arrow-left"
330
+ onActivated: root.close()
331
+ }
332
+ Flea.ChromeButton {
333
+ id: upButton
334
+ ruleRows: Theme.spacing.hairline
335
+ glyph: "arrow-up"
336
+ accessName: "Up unavailable in Trash"
337
+ // Dead by design: a history has no parent, so ChromeButton dims it like any disabled control.
338
+ enabled: false
339
+ Accessible.ignored: false
340
+ }
341
+ Text {
342
+ id: trashTitle
343
+ anchors.verticalCenter: parent.verticalCenter
344
+ text: "Trash"
345
+ textFormat: Text.PlainText
346
+ elide: Text.ElideRight
347
+ color: Theme.color.foreground
348
+ font { family: Theme.font.family; pixelSize: Theme.font.caption }
349
+ }
350
+ Text {
351
+ id: countLabel
352
+ // Both board cells put the count against the title and the action at the far edge, so this row's spare width rides here rather than under the title.
353
+ width: Math.max(implicitWidth, parent.width - 2 * Theme.hitMin - trashTitle.width - emptyAction.width - 4 * parent.spacing)
354
+ anchors.verticalCenter: parent.verticalCenter
355
+ text: Format.count(root.total) + (root.total === 1 ? " item" : " items") + (root.bytesReady ? " · " + (root.bytesPartial ? "≥ " : "") + Format.size(root.totalBytes) : "")
356
+ textFormat: Text.PlainText
357
+ elide: Text.ElideRight
358
+ color: Theme.color.foreground
359
+ font { family: Theme.font.family; pixelSize: Theme.font.caption }
360
+ }
361
+ // Emptying the Trash was reachable only by right-clicking the rail row. It addresses the whole Trash, which is what the count beside it describes, so it belongs here. It opens the confirmation the menu row opens: the boundary is unchanged and no key is bound to it. Disabled exactly where ui/js/Menu.js disables the row.
362
+ Flea.DialogButton {
363
+ id: emptyAction
364
+ anchors.verticalCenter: parent.verticalCenter
365
+ label: "Empty Trash"
366
+ destructive: true
367
+ inStrip: true
368
+ available: root.total > 0 && !root.busy
369
+ onActivated: root.prepare(true)
370
+ }
371
+ }
372
+ Rectangle { anchors.bottom: parent.bottom; width: parent.width; height: Theme.spacing.hairline; color: Theme.color.foreground; opacity: 0.12 }
373
+ }
374
+ Row {
375
+ width: parent.width
376
+ height: Theme.chromeHeight
377
+ leftPadding: Theme.spacing.rowPaddingX
378
+ rightPadding: Theme.spacing.rowPaddingX
379
+ spacing: Theme.spacing.gap
380
+ Item { width: Theme.markSize; height: 1 }
381
+ Text {
382
+ id: nameTitle
383
+ width: Math.max(0, parent.width - Theme.markSize - locationTitle.width - deletedTitle.width - 3 * parent.spacing - parent.leftPadding - parent.rightPadding)
384
+ anchors.verticalCenter: parent.verticalCenter
385
+ text: "Name"
386
+ textFormat: Text.PlainText
387
+ elide: Text.ElideRight
388
+ color: Theme.color.foreground
389
+ font { family: Theme.font.family; pixelSize: Theme.font.caption }
390
+ }
391
+ // The location column is 210 at bodySmall 13; Deleted takes its own body-measured token. Both clamp to preserve the name.
392
+ Text {
393
+ id: locationTitle
394
+ width: Math.min(Math.round(210 * Theme.font.bodySmall / 13), root.width * 0.35)
395
+ anchors.verticalCenter: parent.verticalCenter
396
+ horizontalAlignment: Text.AlignRight
397
+ text: "Original location"
398
+ textFormat: Text.PlainText
399
+ elide: Text.ElideRight
400
+ color: Theme.color.foreground
401
+ font { family: Theme.font.family; pixelSize: Theme.font.caption }
402
+ }
403
+ Text {
404
+ id: deletedTitle
405
+ width: Math.min(Theme.column.trashDate, root.width * 0.2)
406
+ anchors.verticalCenter: parent.verticalCenter
407
+ horizontalAlignment: Text.AlignRight
408
+ text: Sort.title("Deleted", true)
409
+ textFormat: Text.PlainText
410
+ elide: Text.ElideRight
411
+ color: Theme.color.foreground
412
+ font { family: Theme.font.family; pixelSize: Theme.font.caption }
413
+ }
414
+ }
415
+ ListView {
416
+ id: listing
417
+ width: parent.width
418
+ height: Math.max(0, parent.height - 2 * Theme.chromeHeight)
419
+ model: root.opened ? root.total : 0
420
+ clip: true
421
+ reuseItems: true
422
+ boundsBehavior: Flickable.StopAtBounds
423
+ onContentYChanged: root.ensureWindow()
424
+ onHeightChanged: root.ensureWindow()
425
+ TapHandler {
426
+ acceptedButtons: Qt.RightButton
427
+ onTapped: function(point) {
428
+ if (!Tap.onBackground(listing, point)) return
429
+ var at = root.mapFromItem(listing.contentItem, point.position.x, point.position.y)
430
+ root.contextRequested(at.x, at.y, root.selectedCount > 0)
431
+ }
432
+ }
433
+ Flea.FastScrollHandler { flickable: listing }
434
+ Flea.ViewportScrollBar { parent: listing; anchors.top: parent.top; anchors.right: parent.right; flickable: listing }
435
+ delegate: Rectangle {
436
+ id: itemRow
437
+ required property int index
438
+ readonly property var item: root.rowAt(index)
439
+ readonly property bool selected: item && root.isSelected(item.uri)
440
+ width: listing.width
441
+ height: Theme.fileRowHeight
442
+ // HANDOFF rule 7: a marked row takes the OEM's own selection rung, the one ui/Row.qml draws in every listing, rather than an accent wash this surface mixed for itself.
443
+ color: selected ? Style.selectionFill : hover.hovered ? Style.hoverFill : "transparent"
444
+ Rectangle { width: Theme.spacing.hairline * 2; height: parent.height; visible: itemRow.selected; color: Theme.color.accent }
445
+ Row {
446
+ anchors.fill: parent
447
+ anchors.leftMargin: Theme.spacing.rowPaddingX
448
+ anchors.rightMargin: Theme.spacing.rowPaddingX
449
+ spacing: Theme.spacing.gap
450
+ Flea.Glyph { width: Theme.markSize; height: parent.height; name: itemRow.item ? (itemRow.item.directory ? "folder" : Icons.glyphFor(itemRow.item.icon)) : "file"; color: Theme.color.foreground }
451
+ Text { width: Math.max(0, parent.width - Theme.markSize - original.width - deleted.width - 3 * parent.spacing); anchors.verticalCenter: parent.verticalCenter; text: itemRow.item ? itemRow.item.original.split("/").pop() : ""; textFormat: Text.PlainText; elide: Text.ElideRight; color: Theme.color.foreground; font { family: Theme.font.family; pixelSize: Theme.font.body } }
452
+ Text { id: original; width: locationTitle.width; anchors.verticalCenter: parent.verticalCenter; text: itemRow.item ? Trash.location(itemRow.item.original, root.home) : ""; textFormat: Text.PlainText; elide: Text.ElideLeft; horizontalAlignment: Text.AlignRight; color: Theme.color.foreground; font { family: Theme.font.family; pixelSize: Theme.font.body } }
453
+ Text { id: deleted; width: deletedTitle.width; anchors.verticalCenter: parent.verticalCenter; text: itemRow.item ? Trash.deleted(itemRow.item.deleted) : ""; textFormat: Text.PlainText; elide: Text.ElideRight; horizontalAlignment: Text.AlignRight; color: Theme.color.foreground; font { family: Theme.font.family; pixelSize: Theme.font.body } }
454
+ }
455
+ HoverHandler { id: hover }
456
+ Accessible.role: Accessible.ListItem
457
+ Accessible.name: item ? item.original.split("/").pop() : ""
458
+ Accessible.selected: selected
459
+ Accessible.onPressAction: root.choose(itemRow.index, false)
460
+ MouseArea { anchors.fill: parent; acceptedButtons: Qt.LeftButton; onClicked: function(mouse) { root.choose(itemRow.index, mouse.modifiers & Qt.ControlModifier) } }
461
+ TapHandler { acceptedButtons: Qt.RightButton; onTapped: function(point) { if (!itemRow.selected) root.choose(itemRow.index, false); var at = root.mapFromItem(itemRow, point.position.x, point.position.y); root.contextRequested(at.x, at.y, true) } }
462
+ }
463
+ }
464
+ }
465
+ Rectangle { y: 2 * Theme.chromeHeight - height; width: parent.width; height: Theme.spacing.hairline; color: Theme.color.foreground; opacity: 0.12 }
466
+ Text { anchors.centerIn: parent; visible: root.total === 0; text: root.errorText || (root.busy ? "Reading Trash…" : "Trash is empty"); textFormat: Text.PlainText; color: root.errorText ? Theme.color.error : Theme.color.muted; font { family: Theme.font.family; pixelSize: Theme.font.body } }
467
+ // GIO's monitor reports top-level changes; the active confirmation also checks nested identities.
468
+ Timer { interval: 2500; repeat: true; running: root.opened && confirmation.opened && !root.busy; onTriggered: root.send("check", {token: confirmation.snapshot.token}) }
469
+ // m: the cursor row's own menu under that row, the marked rows' menu where it was, the whole-Trash menu when nothing lists.
470
+ function openMenu() {
471
+ var item = rowAt(cursor)
472
+ var target = item ? TrashKeys.menuTarget(total, selectedCount, isSelected(item.uri)) : "strip"
473
+ if (target === "cursor") {
474
+ if (selectedCount === 0) choose(cursor, false)
475
+ listing.positionViewAtIndex(cursor, ListView.Contain)
476
+ var row = listing.itemAtIndex(cursor)
477
+ if (row) {
478
+ var at = row.mapToItem(root, Theme.spacing.rowPaddingX, row.height)
479
+ contextRequested(at.x, at.y, true)
480
+ return
481
+ }
482
+ }
483
+ contextRequested(width / 2, Theme.chromeHeight, selectedCount > 0)
484
+ }
485
+ Flea.TrashConfirm {
486
+ id: confirmation
487
+ parent: root.overlayParent || root
488
+ z: 5
489
+ onConfirmed: function(token) { root.confirming = false; root.send("delete", {token: token}); root.forceActiveFocus() }
490
+ onCancelled: { root.confirming = false; root.send("cancel"); root.forceActiveFocus() }
491
+ }
492
+ }