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,325 @@
1
+ import QtQuick
2
+ import qs.Commons
3
+ import "." as Flea
4
+ import "js/Density.js" as Density
5
+ import "js/Drag.js" as DragOps
6
+ import "js/Format.js" as Format
7
+ import "js/GridNames.js" as GridNames
8
+ import "js/Match.js" as Match
9
+ import "js/Icons.js" as Icons
10
+ import "js/LangMarks.js" as LangMarks
11
+
12
+ // One grid cell: the same mark the list row draws, in a larger slot, with the name under it.
13
+ Item {
14
+ id: root
15
+
16
+ property var row: null
17
+ property bool cursor: false
18
+ property bool hovered: false
19
+ // False while the selection band runs, so the wash keeps the highlight off while the tip still reads hovered.
20
+ property bool hoverShown: true
21
+ property bool selected: false
22
+ property bool dropTarget: false
23
+ property bool dropCopying: false
24
+ property bool dropLinking: false
25
+ property string thumb: ""
26
+ property bool renaming: false
27
+ property var renamePane: null
28
+ // The grid area derives it per visible tile, so an empty clipboard costs nothing.
29
+ property string clipMark: ""
30
+ // A cut tile dims to the ClipMarks board's own opacity, content only.
31
+ readonly property bool clipCut: root.clipMark === "scissors"
32
+ // One dim for the mark slot and the caption, so one ternary serves both opacities.
33
+ readonly property real dimOpacity: root.clipCut ? Theme.disabledOpacity : 1
34
+ // The mark's own size: 12 px in the muted role, 9 px after the name, per the board.
35
+ readonly property int clipPx: Theme.clipMarkSize
36
+ // The query List marks: a search's answered query, else the "/" filter's, "" for none; ui/GridArea.qml hands it down.
37
+ property string markQuery: ""
38
+ // True while the strip is up, so the wash builds with the strip and no keystroke pays for it, as List's rows arm.
39
+ property bool markArmed: false
40
+ readonly property string editorText: renameLoader.item ? renameLoader.item.current : ""
41
+ readonly property Item editorField: renameLoader.item as Item
42
+ // Keep an uninitialized Loader visible; a begun editor's captured index survives retirement.
43
+ visible: !(root.editing || root.pooled) || !renameLoader.item
44
+ || renameLoader.item.editIndex < 0 || !renameLoader.item.viewport
45
+ || renameLoader.item.viewport.renameEditor === renameLoader.item
46
+ // The editor's one line box, centred on the caption's first line on whole pixels: it stands a little over the line's top.
47
+ readonly property real renameLineBox: renameLoader.item ? renameLoader.item.lineBox : Theme.rowHeight - 2 * Theme.spacing.rowPaddingY
48
+ readonly property real renameY: Math.round(nameLabel.y + (Theme.grid.captionLineHeight - root.renameLineBox) / 2)
49
+ readonly property real editorExtraHeight: root.editing && renameLoader.item ? Math.max(0, root.renameY - nameLabel.y + renameLoader.item.implicitHeight - Math.max(Theme.grid.captionHeight, Math.ceil(nameLabel.contentHeight)) - Density.gridPadY(Theme.spacing.rowPaddingX, ViewState.density)) : 0
50
+ property real renameExtraHeight: 0
51
+ // Grid layout can pool this Loader while reading its implicit height. Defer and coalesce per tile.
52
+ onEditorExtraHeightChanged: Qt.callLater(root.applyRenameHeight)
53
+ function applyRenameHeight() {
54
+ if (renameLoader.item) {
55
+ renameLoader.item.queueContainment()
56
+ renameLoader.item.extraHeight = root.editorExtraHeight
57
+ }
58
+ root.renameExtraHeight = root.editorExtraHeight
59
+ }
60
+ signal renameCommitted(string newName)
61
+ signal renameAbandoned()
62
+ function commitEditor() { return renameLoader.item ? renameLoader.item.commit() : false }
63
+
64
+ // A lifted tile is the cursor, the pointer or a selection member, the same ladder Row.qml climbs.
65
+ readonly property bool lifted: root.cursor || (root.hovered && root.hoverShown) || root.selected
66
+ // A thumbnail path is not a thumbnail: the cache file can be evicted between the pane's answer
67
+ // and the decode, and a tile whose Image failed to load has to be marked by its kind instead.
68
+ readonly property bool thumbDrawn: root.thumb.length > 0 && tileThumb.status !== Image.Error
69
+ // One filename lookup; only a mapped row without a thumbnail builds the mark's Loader.
70
+ readonly property string langSlug: ViewState.langMarks ? LangMarks.slugForRow(root.row) : ""
71
+ property var langLoader: null
72
+ function syncLangMark() { LangMarks.syncMark(root, markGlyph, Qt.resolvedUrl("LangMarkLoader.qml"), Component.Ready) }
73
+ onLangSlugChanged: root.syncLangMark()
74
+ onThumbDrawnChanged: root.syncLangMark()
75
+ // The same alias ui/Row.qml carries, so ui/Ipc.qml's rowThumbReady answers for a tile too.
76
+ readonly property alias iconStatus: tileThumb.status
77
+ readonly property Item thumbItem: tileThumb
78
+ readonly property Item captionItem: nameLabel
79
+
80
+ Accessible.role: Accessible.ListItem
81
+ Accessible.name: Match.rowName(root.row, false)
82
+
83
+ Rectangle {
84
+ anchors.fill: parent
85
+ anchors.margins: Theme.spacing.hairline
86
+ color: root.cursor ? Style.selectedAccentFill
87
+ : root.selected ? Style.selectionFill
88
+ : (root.hovered && root.hoverShown) ? Style.hoverFill
89
+ : "transparent"
90
+ // Only the cursor gets a frame; marked tiles retain their separate fill.
91
+ border.width: root.cursor ? Theme.spacing.hairline : 0
92
+ border.color: Theme.color.accent
93
+ }
94
+
95
+ // The drop wash, and its label further down, build only on the tile under a drag, the way ui/Row.qml builds its drop frame.
96
+ Loader {
97
+ anchors.fill: parent
98
+ active: root.dropTarget
99
+ sourceComponent: Rectangle {
100
+ color: Util.alpha(Theme.color.accent, Style.hoverFillAlpha)
101
+ border.width: Theme.spacing.hairline
102
+ border.color: Theme.color.accent
103
+ }
104
+ }
105
+
106
+ Item {
107
+ id: markSlot
108
+ anchors.horizontalCenter: parent.horizontalCenter
109
+ anchors.top: parent.top
110
+ anchors.topMargin: Density.gridPadY(Theme.spacing.rowPaddingX, ViewState.density)
111
+ width: ViewState.thumbnailPixels
112
+ height: ViewState.thumbnailPixels
113
+ opacity: root.dimOpacity
114
+
115
+ // A thumbnail is a decoded image and stays one; the glyph beside it is a native mark, and
116
+ // exactly one is visible, chosen the same way ui/Row.qml chooses.
117
+ Image {
118
+ id: tileThumb
119
+ anchors.fill: parent
120
+ visible: root.thumbDrawn
121
+ // Format.fileUri, not a concatenation: a cache path can carry a # or a ? and either one
122
+ // silently truncates a plain file:// URL, which is what the hashcache fixture proves.
123
+ source: root.thumb.length > 0 ? Format.fileUri(root.thumb) : ""
124
+ fillMode: Image.PreserveAspectFit
125
+ sourceSize.width: ViewState.thumbnailPixels
126
+ sourceSize.height: ViewState.thumbnailPixels
127
+ asynchronous: true
128
+ cache: false
129
+ }
130
+
131
+ Flea.Glyph {
132
+ id: markGlyph
133
+ anchors.fill: parent
134
+ visible: !root.thumbDrawn && root.langSlug === ""
135
+ // A folder mark never grows past 128, centred in the larger slots, so only thumbnails grow.
136
+ maxSize: Density.glyphCap(ViewState.thumbnailPixels)
137
+ name: root.row ? Icons.glyphForRow(root.row.i, root.row.p) : "file"
138
+ // ThemeRoles.dc.html gives accent the selection fill and edge and foreground the label
139
+ // and the mark inside it, so the border carries the emphasis and the ink stays readable.
140
+ color: root.cursor || root.selected ? Theme.color.foreground : Theme.color.mutedFrame
141
+ }
142
+ }
143
+
144
+ // One drawn line's piece of the match wash, at the box the mark measured for it.
145
+ component MatchWash: Rectangle {
146
+ id: wash
147
+ property var box: null
148
+ visible: wash.box !== null
149
+ x: wash.box ? wash.box.x : 0
150
+ y: wash.box ? wash.box.y : 0
151
+ width: wash.box ? wash.box.width : 0
152
+ }
153
+
154
+ // List's match mark, ui/MatchText.qml's wash behind the matched letters under the unchanged caption, built with the strip.
155
+ Loader {
156
+ id: markLoader
157
+ active: root.markArmed || root.markQuery.length > 0
158
+ visible: !root.editing
159
+ opacity: root.dimOpacity
160
+ x: nameLabel.x
161
+ y: nameLabel.y
162
+ width: nameLabel.width
163
+ height: nameLabel.height
164
+ sourceComponent: Item {
165
+ id: washes
166
+ FontMetrics { id: captionFace; font: nameLabel.font }
167
+ // Only lines Qt drew as Flea broke them are measured; a caption Qt wrapped or elided again would place a box off its letters.
168
+ readonly property bool laidAsBroken: nameLabel.lineCount === nameLabel.text.split("\n").length && !nameLabel.truncated
169
+ readonly property var boxes: washes.laidAsBroken ? washes.measure(GridNames.captionMarks(nameLabel.text, root.markQuery), captionFace.font, washes.width) : []
170
+ // One box per line the run touches; face is read only so a font change re-measures, as RenameField's edgeX does.
171
+ function measure(spans, face, width) {
172
+ return spans.map(function (span) {
173
+ return { x: (width - captionFace.advanceWidth(span.centred)) / 2 + captionFace.advanceWidth(span.before),
174
+ y: span.line * Theme.grid.captionLineHeight, width: captionFace.advanceWidth(span.run) }
175
+ })
176
+ }
177
+ readonly property color wash: Qt.rgba(Theme.color.accent.r, Theme.color.accent.g, Theme.color.accent.b, Theme.color.accent.a * Theme.washActive)
178
+ MatchWash { box: washes.boxes.length > 0 ? washes.boxes[0] : null; height: Math.ceil(captionFace.height); color: washes.wash }
179
+ MatchWash { box: washes.boxes.length > 1 ? washes.boxes[1] : null; height: Math.ceil(captionFace.height); color: washes.wash }
180
+ }
181
+ }
182
+
183
+ // corner: a filename is arbitrary text, so PlainText; the breaks are Flea's own, WrapAnywhere only catches wide glyphs.
184
+ readonly property int captionLines: root.dropTarget ? 1 : 2
185
+ // Cells of one caption line at the bodySmall advance the label draws at; a wide glyph counts two.
186
+ readonly property int captionPerLine: Theme.bodySmallAdvance > 0 && nameLabel.width > 0 ? Math.floor(nameLabel.width / Theme.bodySmallAdvance) : -1
187
+ Text {
188
+ id: nameLabel
189
+ visible: !root.editing
190
+ opacity: root.dimOpacity
191
+ anchors.top: markSlot.bottom
192
+ anchors.topMargin: Theme.spacing.gap
193
+ anchors.left: parent.left
194
+ anchors.right: parent.right
195
+ anchors.leftMargin: Theme.spacing.gap
196
+ anchors.rightMargin: Theme.spacing.gap + (root.clipMark.length > 0 ? Theme.spacing.gap + root.clipPx : 0)
197
+ // The slot fits the laid-out text, keeping the token reserve as its minimum.
198
+ height: Math.max(root.dropTarget ? Theme.grid.captionLineHeight : Theme.grid.captionHeight, Math.ceil(contentHeight))
199
+ horizontalAlignment: Text.AlignHCenter
200
+ text: root.row ? GridNames.gridCaption(Match.rowName(root.row, false), root.captionPerLine, root.captionLines) : ""
201
+ color: Theme.color.foreground
202
+ font.family: Theme.font.family
203
+ font.pixelSize: Theme.font.bodySmall
204
+ textFormat: Text.PlainText
205
+ wrapMode: Text.WrapAnywhere
206
+ maximumLineCount: root.captionLines
207
+ lineHeightMode: Text.FixedHeight
208
+ lineHeight: Theme.grid.captionLineHeight
209
+ elide: Text.ElideRight
210
+ }
211
+
212
+ // A tagged tile mounts its swatches (ui/TagSlot.qml) under the caption on first need; an untagged tile builds nothing.
213
+ property var tagItem: null
214
+ onRowChanged: root.syncTags()
215
+ onRenamingChanged: root.syncTags()
216
+ function syncTags() {
217
+ var names = root.row && !root.renaming ? root.row.tg : undefined
218
+ if (root.tagItem !== null) root.tagItem.tags = names || []
219
+ else if (names !== undefined) root.tagItem = Qt.createComponent("TagSlot.qml").createObject(root, { tags: names, below: nameLabel })
220
+ }
221
+
222
+ // Built only on a clipboard tile: a Glyph per tile costs a Shape, and the mark follows the last line it sits beside.
223
+ Loader {
224
+ id: clipLoader
225
+ active: root.clipMark.length > 0 && !root.editing
226
+ width: root.clipPx
227
+ height: root.clipPx
228
+ // One gap past the centred last line's own right end, capped at the strip the margin reserves; a tile with no mark measures nothing.
229
+ x: clipLoader.active ? Math.min(nameLabel.x + (nameLabel.width + GridNames.lastLineCells(nameLabel.text) * Theme.bodySmallAdvance) / 2 + Theme.spacing.gap, nameLabel.x + nameLabel.width + Theme.spacing.gap) : 0
230
+ y: clipLoader.active ? nameLabel.y + Math.min(nameLabel.text.split("\n").length, root.captionLines) * Theme.grid.captionLineHeight - (Theme.grid.captionLineHeight + root.clipPx) / 2 - 1 : 0
231
+ sourceComponent: Flea.Glyph {
232
+ width: root.clipPx
233
+ height: root.clipPx
234
+ name: root.clipMark
235
+ color: Theme.color.mutedFrame
236
+ }
237
+ }
238
+
239
+ // Built only while renaming, the way ui/Row.qml builds its own editor.
240
+ Loader {
241
+ id: renameLoader
242
+ active: root.pooled ? root.pooledEditorRow >= 0 : root.renaming
243
+ anchors { left: nameLabel.left; right: nameLabel.right }
244
+ y: root.renameY
245
+ // A normal editor's expansion starts and stays zero, so no height-change signal measures it.
246
+ onLoaded: Qt.callLater(root.applyRenameHeight)
247
+ sourceComponent: Flea.RenameField {
248
+ height: implicitHeight
249
+ editorHost: root
250
+ pane: root.renamePane
251
+ viewport: root.GridView.view
252
+ containOnBegin: true
253
+ name: root.row ? root.row.n.split("/").pop() : ""
254
+ onCommitted: function(newName) { root.renameCommitted(newName) }
255
+ onAbandoned: root.renameAbandoned()
256
+ }
257
+ }
258
+
259
+ Loader {
260
+ anchors.top: nameLabel.bottom
261
+ anchors.left: nameLabel.left
262
+ anchors.right: nameLabel.right
263
+ height: Theme.grid.captionLineHeight
264
+ active: root.dropTarget
265
+ sourceComponent: Text {
266
+ horizontalAlignment: Text.AlignHCenter
267
+ text: DragOps.label(root.dropCopying, root.dropLinking)
268
+ color: Theme.color.accent
269
+ font.family: Theme.font.family
270
+ font.pixelSize: Theme.font.caption
271
+ textFormat: Text.PlainText
272
+ elide: Text.ElideRight
273
+ }
274
+ }
275
+
276
+ // Flea elides the caption itself, so Qt reports truncated only when it had to cut a caption Flea handed over whole.
277
+ function captionElided() {
278
+ return nameLabel.truncated || (root.row ? nameLabel.text.split("\n").join("") !== String(Match.rowName(root.row, false)) : false)
279
+ }
280
+
281
+ // Built only while the host's hover rests on a truncated caption: its size reads the wrapped name's layout, which every tile paid at rest.
282
+ Loader {
283
+ objectName: "nameTip"
284
+ active: !root.editing && !root.dropTarget && root.hovered && root.captionElided()
285
+ z: 1
286
+ anchors.horizontalCenter: parent.horizontalCenter
287
+ anchors.top: nameLabel.bottom
288
+ anchors.topMargin: Theme.spacing.hairline
289
+ sourceComponent: Rectangle {
290
+ width: Math.min(tip.implicitWidth + 2 * Theme.spacing.gap, Theme.grid.minCellWidth * 2)
291
+ height: tip.implicitHeight + Theme.spacing.gap
292
+ color: Theme.color.surface
293
+ border.width: Theme.spacing.hairline
294
+ border.color: Theme.color.mutedFrame
295
+
296
+ Text {
297
+ id: tip
298
+ anchors.centerIn: parent
299
+ width: parent.width - 2 * Theme.spacing.gap
300
+ text: Match.rowName(root.row, false)
301
+ color: Theme.color.foreground
302
+ font.family: Theme.font.family
303
+ font.pixelSize: Theme.font.caption
304
+ wrapMode: Text.Wrap
305
+ textFormat: Text.PlainText
306
+ }
307
+ }
308
+ }
309
+
310
+ // Pooled by its view, which parks the tile's listing reads on live (ui/GridArea.qml); a pooled tile builds no editor.
311
+ property bool pooled: false
312
+ readonly property bool live: !root.pooled
313
+ // The row whose editor the tile held when pooled, -1 for none; it keeps that editor while the edit stays on that row.
314
+ property int pooledEditorRow: -1
315
+ // The pane's edit row as a pooled tile sees it; once the edit leaves the recorded row the record clears for good.
316
+ readonly property int pooledRename: root.pooled && root.renamePane !== null ? root.renamePane.renamingIndex : -1
317
+ onPooledRenameChanged: if (root.pooledEditorRow >= 0 && root.pooledRename !== root.pooledEditorRow) root.pooledEditorRow = -1
318
+ // Drawn as the editing tile: renaming, or pooled with the editor it held.
319
+ readonly property bool editing: root.renaming || root.pooled && root.pooledEditorRow >= 0
320
+ GridView.onPooled: { root.pooledEditorRow = root.renaming && root.renamePane !== null ? root.renamePane.renamingIndex : -1; root.pooled = true }
321
+ // The kept editor drops first, while every listing read is still parked, so its retirement always owns the edit.
322
+ GridView.onReused: { root.pooledEditorRow = -1; root.pooled = false }
323
+ // What the grid last drew here (GridGeometry.heldRow), a plain object no binding tracks.
324
+ readonly property var rowMemo: ({ row: null, index: -1, listing: 0 })
325
+ }
@@ -0,0 +1,164 @@
1
+ import QtQuick
2
+ import Quickshell
3
+ import Quickshell.Io
4
+ import "js/GvfsBridge.js" as GvfsBridge
5
+
6
+ // Phones and shares open through the GVFS FUSE bridge at $XDG_RUNTIME_DIR/gvfs, and gvfsd
7
+ // spawns its own bridge once at its startup only, so one that died stays down until
8
+ // something starts it again. ensure() checks the folder first: a served one opens at once
9
+ // and starts nothing, an unserved one starts gvfsd-fuse's own argv a single time and the
10
+ // folder opening waits for the folder rather than for the process. The window stays put
11
+ // either way until ready() carries the folder, and failed() carries the board's error line.
12
+ // Local folders never reach here: ui/NetworkMounts.qml only ensures FUSE paths gio resolved.
13
+ //
14
+ // This service lives in the window-long network host rather than in the rail, so hiding the
15
+ // rail mid-wait kills no wait: the ready or the failure still lands and the Starting line it
16
+ // showed still clears. The bridge itself starts detached, so closing the rail or the chooser
17
+ // never takes gvfsd-fuse down with it; no exit status ever reaches the board, and the whole
18
+ // ensure's own deadline is the failure signal instead.
19
+ Item {
20
+ id: root
21
+
22
+ signal ready(string path, var origin, bool isDir)
23
+ signal starting(string text, var origin)
24
+ signal failed(string text, var origin)
25
+ signal notice(string text, var origin)
26
+
27
+ // The test seam: FLEA_GVFS_FUSE names a fake bridge command the way FLEA_BIN names one.
28
+ property string fuseEnv: Quickshell.env("FLEA_GVFS_FUSE") || ""
29
+ property string runtimeDir: Quickshell.env("XDG_RUNTIME_DIR") || ""
30
+ // Which question checkProcess is answering: the directory check, the file check, a wait
31
+ // poll or the classify after a poll landed.
32
+ property string pendingMode: ""
33
+ // Set beside the deadline's own kill so the helper's late exit answers nothing: the
34
+ // deadline already failed the wait, and that exit belongs to no waiter anymore.
35
+ property bool _ensureTimedOut: false
36
+
37
+ // D-103: flow, never state, which shadows Item.state and was the tree's own qmllint
38
+ // property-override.
39
+ property var flow: GvfsBridge.create()
40
+
41
+ function dir() { return GvfsBridge.bridgeDir(root.runtimeDir) }
42
+
43
+ function ensure(path, label, origin) {
44
+ root.run(GvfsBridge.ensure(root.flow, { path: path, label: label, origin: origin,
45
+ bridgeDir: root.dir(), fuseBin: GvfsBridge.fuseBin(root.fuseEnv) }))
46
+ }
47
+
48
+ function cancel() {
49
+ root.pendingMode = ""
50
+ if (checkProcess.running) { root._ensureTimedOut = true; checkProcess.running = false }
51
+ root.stopWaiting()
52
+ root.run(GvfsBridge.cancel(root.flow))
53
+ }
54
+
55
+ // A dialog cancel ends only its own flight's waiter; another flight's wait stands.
56
+ function cancelFor(origin) {
57
+ var waiter = root.flow.waiter
58
+ if (waiter && origin !== null && waiter.origin !== origin) return
59
+ root.cancel()
60
+ }
61
+
62
+ function run(actions) {
63
+ for (var i = 0; i < actions.length; i++) {
64
+ var action = actions[i]
65
+ if (action.op === "check" || action.op === "checkFile" || action.op === "classify") {
66
+ root.pendingMode = action.op
67
+ // Directories answer -d, anything else -e: a file under a live bridge is ready
68
+ // without any start, and only a path that is neither starts one.
69
+ checkProcess.command = action.op === "check" || action.op === "classify"
70
+ ? ["test", "-d", action.path] : ["test", "-e", action.path]
71
+ checkProcess.running = true
72
+ ensureDeadline.restart()
73
+ } else if (action.op === "start") {
74
+ // Detached on purpose: an attached child dies with this service, and killing the
75
+ // rail or the chooser must never take gvfsd-fuse down for every app. There is no
76
+ // exit to wait for, so the folder poll below is the whole failure signal; the
77
+ // single flight in ensure() above is what keeps one wait to one start, because a
78
+ // detached spawn cannot be told apart from another one by a running flag.
79
+ Quickshell.execDetached(action.argv)
80
+ pollTimer.restart()
81
+ startingTimer.restart()
82
+ ensureDeadline.restart()
83
+ } else if (action.op === "ready") {
84
+ root.stopWaiting()
85
+ root.ready(action.path, action.origin, action.isDir)
86
+ } else if (action.op === "show") {
87
+ root.starting(action.text, action.origin)
88
+ } else if (action.op === "fail") {
89
+ root.stopWaiting()
90
+ root.failed(action.text, action.origin)
91
+ } else if (action.op === "refuse") {
92
+ root.notice(action.text, action.origin)
93
+ }
94
+ }
95
+ }
96
+
97
+ function stopWaiting() {
98
+ ensureDeadline.stop()
99
+ pollTimer.stop()
100
+ startingTimer.stop()
101
+ }
102
+
103
+ // One deadline for the whole ensure, checking, file-checking, waiting and classifying.
104
+ // Whichever leg is still running when it fires is the one that missed it. The flag is set
105
+ // only beside a real kill, so a deadline that lands between two helpers arms nothing for a
106
+ // later wait to swallow: one kill pairs with exactly one late exit.
107
+ Timer {
108
+ id: ensureDeadline
109
+ interval: GvfsBridge.ENSURE_MS
110
+ repeat: false
111
+ onTriggered: {
112
+ if (root.flow.phase === "idle" && !root.flow.waiter)
113
+ return
114
+ if (checkProcess.running) {
115
+ root._ensureTimedOut = true
116
+ checkProcess.running = false
117
+ }
118
+ root.stopWaiting()
119
+ root.run(GvfsBridge.onTimeout(root.flow))
120
+ }
121
+ }
122
+
123
+ Timer {
124
+ id: startingTimer
125
+ interval: GvfsBridge.STARTING_MS
126
+ repeat: false
127
+ onTriggered: root.run(GvfsBridge.onElapsed(root.flow))
128
+ }
129
+
130
+ Timer {
131
+ id: pollTimer
132
+ interval: GvfsBridge.POLL_MS
133
+ repeat: true
134
+ onTriggered: {
135
+ if (checkProcess.running || !root.flow.waiter
136
+ || root.flow.phase !== "waiting")
137
+ return
138
+ root.pendingMode = "poll"
139
+ checkProcess.command = ["test", "-e", root.flow.waiter.path]
140
+ checkProcess.running = true
141
+ }
142
+ }
143
+
144
+ Process {
145
+ id: checkProcess
146
+ onExited: function (exitCode) {
147
+ if (root._ensureTimedOut) {
148
+ root._ensureTimedOut = false
149
+ root.pendingMode = ""
150
+ return
151
+ }
152
+ var mode = root.pendingMode
153
+ root.pendingMode = ""
154
+ if (mode === "poll")
155
+ root.run(GvfsBridge.onPolled(root.flow, exitCode === 0))
156
+ else if (mode === "checkFile")
157
+ root.run(GvfsBridge.onCheckedFile(root.flow, exitCode === 0))
158
+ else if (mode === "classify")
159
+ root.run(GvfsBridge.onClassified(root.flow, exitCode === 0))
160
+ else
161
+ root.run(GvfsBridge.onChecked(root.flow, exitCode === 0))
162
+ }
163
+ }
164
+ }