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,24 @@
1
+ import QtQuick
2
+ import "js/Format.js" as Format
3
+
4
+ // The moving layer over a still GIF frame, built by its host only once that frame is drawn; the host's Loader holds the still's rect and this fills it.
5
+ AnimatedImage {
6
+ id: root
7
+
8
+ property string path: ""
9
+ // False while the host's picture is covered or off screen.
10
+ property bool shown: true
11
+ // The window is mapped and not minimised; a hidden window pauses on its current frame.
12
+ readonly property bool exposed: Window.window !== null && Window.window.visible
13
+ && Window.visibility !== Window.Hidden && Window.visibility !== Window.Minimized
14
+ // True from the frame its own first frame is ready, which is when the host stops drawing the still.
15
+ readonly property bool ready: root.status === Image.Ready && root.frameCount > 1
16
+
17
+ anchors.fill: parent
18
+ opacity: root.ready ? 1 : 0
19
+ source: root.path.length > 0 ? Format.fileUri(root.path) : ""
20
+ fillMode: Image.Stretch
21
+ playing: root.visible && root.shown && root.exposed
22
+ asynchronous: true
23
+ cache: false
24
+ }
@@ -0,0 +1,91 @@
1
+ import QtQuick
2
+ import qs.Commons
3
+ import "." as Flea
4
+ import "js/Facts.js" as Facts
5
+ import "js/Format.js" as Format
6
+ import "js/Archive.js" as Archive
7
+
8
+ // The Archive tile's frame: the entries the wire carried, as many as the frame has room for, and the
9
+ // count it could not name. One row per line box, less the "+ N more" line, which always has to be
10
+ // visible: a list that ran past the frame would hide the very number it exists to state.
11
+ Item {
12
+ id: root
13
+
14
+ // The meta answer for the archive row, or null before one has arrived.
15
+ property var meta: null
16
+ property string path: ""
17
+ property var pane: null
18
+ readonly property bool extractable: pane !== null && /\.(zip|tar|tar\.gz|tgz|tar\.zst|tzst)$/i.test(path) && meta !== null && !meta.archiveFailed
19
+
20
+ Flow {
21
+ id: actions
22
+ width: parent.width
23
+ spacing: Theme.spacing.gap
24
+ visible: root.extractable
25
+ Flea.DialogButton {
26
+ label: "Extract to Folder"
27
+ tabStop: true
28
+ onActivated: {
29
+ var base = root.path.substring(0, root.path.lastIndexOf("/") + 1)
30
+ root.pane.backend.extract(root.path, base + Archive.extractDir(root.path.substring(base.length)), 0)
31
+ }
32
+ }
33
+ Flea.DialogButton {
34
+ label: "Extract here"
35
+ tabStop: true
36
+ onActivated: root.pane.extractHereRequested(root.path, root.meta && typeof root.meta.topEntries === "number" ? root.meta.topEntries : -1)
37
+ }
38
+ }
39
+
40
+ readonly property real lineHeight: Math.round(Theme.font.caption * Theme.lineBoxRatio)
41
+ readonly property int shown: Math.max(0, Math.floor((height - (actions.visible ? actions.height + Theme.spacing.gap : 0)) / lineHeight) - 1)
42
+
43
+ Column {
44
+ anchors.fill: parent
45
+ anchors.topMargin: actions.visible ? actions.height + Theme.spacing.gap : 0
46
+ clip: true
47
+ spacing: 0
48
+
49
+ Repeater {
50
+ model: Facts.archiveEntries(root.meta, root.shown)
51
+
52
+ delegate: Row {
53
+ required property var modelData
54
+ width: root.width
55
+ height: root.lineHeight
56
+ spacing: Theme.spacing.gap
57
+
58
+ Flea.Glyph {
59
+ anchors.verticalCenter: parent.verticalCenter
60
+ width: Theme.font.caption
61
+ height: Theme.font.caption
62
+ name: modelData.d ? "folder" : "file"
63
+ color: Theme.color.mutedFrame
64
+ }
65
+
66
+ // corner: an archive holds arbitrary names, so PlainText; the row's height, centred, puts the name on the glyph's line.
67
+ Text {
68
+ height: parent.height
69
+ verticalAlignment: Text.AlignVCenter
70
+ text: modelData.n
71
+ color: Theme.color.muted
72
+ font.family: Theme.font.family
73
+ font.pixelSize: Theme.font.caption
74
+ textFormat: Text.PlainText
75
+ elide: Text.ElideRight
76
+ }
77
+ }
78
+ }
79
+
80
+ Text {
81
+ height: root.lineHeight
82
+ visible: Facts.archiveMore(root.meta, root.shown) > 0
83
+ text: "+ " + Format.count(Facts.archiveMore(root.meta, root.shown)) + " more"
84
+ color: Theme.color.muted
85
+ opacity: 0.6
86
+ font.family: Theme.font.family
87
+ font.pixelSize: Theme.font.caption
88
+ textFormat: Text.PlainText
89
+ }
90
+ }
91
+ }
@@ -0,0 +1,553 @@
1
+ import QtQuick
2
+ import qs.Commons
3
+ import "." as Flea
4
+ import "js/Facts.js" as Facts
5
+ import "js/PreviewKeys.js" as PreviewKeys
6
+ import "js/Format.js" as Format
7
+ import "js/Icons.js" as Icons
8
+ import "js/KeyName.js" as KeyName
9
+ import "js/Kinds.js" as Kinds
10
+ import "js/Thumbs.js" as Thumbs
11
+ import "js/ExtThumbs.js" as ExtThumbs
12
+ // The columns view's last pane when a file is picked. One anatomy for all twelve states the canvas
13
+ // draws: a frame, an optional transport, the name, and a caption-type table of facts under it.
14
+ Item {
15
+ id: root
16
+
17
+ property var row: null
18
+ // The meta reply's own fields, whatever ui/Backend.qml's meta signal carries; null until it arrives.
19
+ property var meta: null
20
+ property string kindName: ""
21
+ property string thumb: ""
22
+ // ExtThumbs: a class that is off holds the frame on its facts until Ctrl+Space loads it.
23
+ property bool manualHold: false
24
+ // ExtThumbs: how much of a text file the frame may read; 256 KiB on network and phone storage.
25
+ property int textLimit: 1048576
26
+ // True where the board truncates instead of refusing: an over-limit remote file shows its first bytes.
27
+ property bool truncateText: false
28
+ // True once no thumbnail is coming: the backend answered with none, or never offered one at all.
29
+ property bool noThumbComing: false
30
+ // A move cleared the row and its settle is running, so the column is loading, not showing a file with no preview.
31
+ property bool pending: false
32
+ // Set by ui/PreviewSwap.qml when a hold ran out, which already spent LoadingState's own hold-off.
33
+ property bool loadingHeldOff: false
34
+ property int selectionCount: 0
35
+ property var selectedRows: []
36
+ property string path: ""
37
+ readonly property real pdfScrollY: pdfFlick.contentY
38
+ readonly property var pdfFrameItem: frame
39
+ signal expandRequested()
40
+ // No player exists until the operator presses play. The strip draws from the probe's own
41
+ // duration, so browsing a folder of clips builds no MediaPlayer at all: it costs nothing, makes
42
+ // no sound, and stops QtMultimedia logging a teardown warning on every cursor move.
43
+ property bool wantsPlayback: false
44
+ // The shared Space preview, handed in by ui/ColumnsArea.qml: one file plays in one place.
45
+ property bool overlayOpen: false
46
+ // Where a player may exist at all: this column on screen, no overlay over it, and a strip to drive it; losing any of them ends the play intent.
47
+ readonly property bool playerAllowed: root.visible && !root.overlayOpen && mediaLoader.active
48
+ onPlayerAllowedChanged: if (!root.playerAllowed) root.wantsPlayback = false
49
+
50
+ // A new row is a new subject, so whatever was playing stops being this column's business, and
51
+ // the player it needed is torn down with it.
52
+ onPathChanged: root.wantsPlayback = false
53
+
54
+ // What the row itself is, before Loading or Error can override it. The readers below are built
55
+ // from this and never from previewState: an error that switched its own reader off would clear
56
+ // the error, re-enter the read, and flap between the two states forever.
57
+ readonly property string rowState: root.row !== null && root.row.d !== true
58
+ ? Facts.state(root.row, 1, false, "", root.kindName) : ""
59
+
60
+ // Loading and Error are states the column reaches on its own: loading while the facts are still
61
+ // in flight, and error when the thing it was going to draw could not be read at all. A held
62
+ // frame is neither: its facts are the listing's own and there is nothing in flight.
63
+ readonly property bool busy: root.pending || (root.row !== null && root.row.d !== true && root.meta === null && !root.manualHold)
64
+ readonly property string pdfSentence: pdfLoader.item ? pdfLoader.item.failSentence : ""
65
+ readonly property string failure: lines.readFailed || root.pdfFailed || (root.isHtmlRow && root.markdown && root.markdown.failed)
66
+ ? (root.pdfFailed && root.pdfSentence.length > 0 ? root.pdfSentence : "This file could not be read.")
67
+ : (root.meta && root.meta.archiveFailed ? "This archive could not be read." : "")
68
+
69
+ // The PDF reader exists only for a PDF row, the same rule the media transport follows: browsing
70
+ // a folder of anything else builds no PdfDocument at all.
71
+ readonly property int pdfPages: pdfLoader.item ? pdfLoader.item.pageCount : 0
72
+ readonly property bool pdfFailed: pdfLoader.item ? pdfLoader.item.failed : false
73
+ readonly property bool pdfDrawn: pdfLoader.item ? pdfLoader.item.shownPage >= 0 : false
74
+
75
+ readonly property string previewState: Facts.state(root.row, root.selectionCount, root.busy, root.failure, root.kindName)
76
+ // What the rows and the facts line state that the listing and the meta reply do not carry.
77
+ readonly property var factExtra: ({ pages: root.pdfPages > 0 ? String(root.pdfPages) : "",
78
+ owner: root.meta && root.meta.owner ? root.meta.owner : "" })
79
+ readonly property var factRows: root.previewState === Facts.MULTI
80
+ ? Facts.multiFacts(root.selectedRows, root.selectionCount)
81
+ : (root.row ? Facts.facts(root.previewState, root.row, root.meta, root.kindName, root.factExtra) : [])
82
+
83
+ // The canvas's frame is 16 by 10, the one proportion every state shares but a tall kind's, which fills the column down to the name.
84
+ readonly property real frameRatio: 10 / 16
85
+ readonly property bool tallRow: root.previewState !== Facts.MULTI && Facts.tall(root.rowState)
86
+ // Document rows always render in the tall column frame, independently of Quick Look.
87
+ readonly property bool isMarkdownRow: root.rowState === Facts.TEXT && root.row !== null
88
+ && root.row.s <= root.textLimit && Kinds.isMarkdown(root.row.n)
89
+ // An office document is converted by the backend, so it needs local storage and has its own size gate.
90
+ readonly property bool isOfficeRow: root.rowState === Facts.TEXT && root.row !== null && !root.truncateText
91
+ && root.row.s <= Kinds.OFFICE_LIMIT && Kinds.isOfficeDocument(root.row.n)
92
+ readonly property bool isHtmlRow: root.isOfficeRow || (root.rowState === Facts.CODE && root.row !== null && root.row.s <= root.textLimit && Kinds.isHtml(root.row.n))
93
+ readonly property bool isDocumentRow: root.isMarkdownRow || root.isHtmlRow
94
+ // The document pane stays null without a document row, so every reader guards the loader item.
95
+ readonly property var markdown: markdownLoader.item
96
+ // The document reader's activation is shared by the Loader and its item so the two cannot drift apart.
97
+ readonly property bool markdownActive: root.visible && !root.manualHold && root.isDocumentRow && (!root.isHtmlRow || root.selectionCount <= 1)
98
+ // Stretch renders a vector to the whole box, so the frame's pictures keep Fit for an SVG alone.
99
+ readonly property bool vectorPath: /\.svgz?$/i.test(root.path)
100
+ // EXIF orientations 5 to 8 swap the sides, and Qt fits its decode before it turns, so the box it is asked for turns too.
101
+ readonly property bool turned: root.meta !== null && root.meta.orient >= 5
102
+
103
+ // The states that draw a picture of the file itself. A PDF draws its own page, loading draws the
104
+ // crawl, and a multi-selection is a summary and never the cursor row's own picture.
105
+ readonly property bool wantsThumb: root.previewState !== Facts.LOADING
106
+ && root.previewState !== Facts.PDF && root.previewState !== Facts.MULTI
107
+ // A thumbnail path is not a thumbnail: the cache file can be evicted between the pane's answer
108
+ // and the decode, and an Image that failed to load draws nothing at all. The fallback waits for
109
+ // Ready instead, because a file off a slow mount would leave the frame blank for seconds.
110
+ readonly property bool thumbDrawn: root.thumb.length > 0 ? frameThumb.status !== Image.Error
111
+ : frameThumb.status === Image.Ready
112
+ readonly property bool thumbShown: root.wantsThumb && root.thumbDrawn
113
+ // For ui/Ipc.qml's columnFrameRect: the box a playing video's pixels must change inside.
114
+ readonly property Item frameItem: frame
115
+ // For ui/Ipc.qml's columnPictureRect: the player's content rect while it plays, else the poster;
116
+ // frameThumb keeps its geometry hidden under the player, so reading it then measures a stale poster.
117
+ readonly property Item pictureItem: playerLoader.visible && playerLoader.item ? playerLoader.item.contentItem : frameThumb
118
+ readonly property Item linesItem: lines
119
+ readonly property Item archiveItem: archivePane
120
+ readonly property alias factsLine: facts.line
121
+ // A 3D model's original is never decoded: Qt has no plugin for it, and each attempt logs a warning.
122
+ readonly property bool originalRefused: Kinds.isModel(root.path)
123
+ // Ready is the decoded picture (thumbShown is true while it loads); a model with no thumbnail coming reads Error, which ui/js/PreviewSwap.js treats as settled.
124
+ readonly property int frameStatus: root.originalRefused && root.thumb.length === 0 && root.noThumbComing ? Image.Error : frameThumb.status
125
+ // The two states whose picture is the thumbnail; audio's mark is what that state draws when it works.
126
+ readonly property bool picturesFromThumb: root.previewState === Facts.IMAGE || root.previewState === Facts.VIDEO
127
+
128
+ // One mark per kind in the selection, front-most first; ui/KindStack.qml stacks them.
129
+ readonly property var multiMarks: root.previewState === Facts.MULTI
130
+ ? Facts.multiMarks(root.selectedRows) : []
131
+
132
+ Column {
133
+ anchors.fill: parent
134
+ anchors.margins: Theme.spacing.rowPaddingX
135
+ spacing: Theme.spacing.gap
136
+
137
+ Rectangle {
138
+ id: frame
139
+ width: parent.width
140
+ height: root.tallRow ? Facts.tallHeight(root.height, Theme.spacing.rowPaddingX, nameText.height, facts.height, Theme.spacing.gap) : Math.round(width * root.frameRatio)
141
+ // The listing's own colour, so on glass the pane's ground under it is the fill; see ui/Glass.qml.
142
+ color: Glass.on ? "transparent" : Theme.color.background
143
+ border.width: Theme.spacing.hairline
144
+ border.color: Theme.color.mutedFrame
145
+ // Mirrors hyprland decoration:rounding, the same as every other floating chrome surface.
146
+ radius: Style.cornerRadius
147
+ clip: true
148
+
149
+ // The thumbnail subsystem's own surface: a real thumbnail when there is one, the kind's
150
+ // mark when there is not, which is what the canvas means by "the glyph stands in here".
151
+ // Sized the way ui/PreviewImage.qml sizes its picture, and for its reasons: the exact fit, never enlarged in the decode.
152
+ Image {
153
+ id: frameThumb
154
+ readonly property real boxWidth: parent.width - 2 * Theme.spacing.hairline
155
+ readonly property real boxHeight: parent.height - 2 * Theme.spacing.hairline
156
+ readonly property bool vector: root.thumb.length === 0 && root.vectorPath
157
+ // The fallback is the original, so never enlarged; a cache file up to the original's own size.
158
+ // A video poster is the exception: it draws at the player's size, enlarged when the clip is small.
159
+ readonly property real fit: Thumbs.fitScale(boxWidth, boxHeight, implicitWidth, implicitHeight, root.thumb.length === 0 ? 1
160
+ : Thumbs.posterLimit(root.previewState === Facts.VIDEO, implicitWidth, implicitHeight, root.meta ? root.meta.w : 0, root.meta ? root.meta.h : 0))
161
+ x: vector ? Theme.spacing.hairline : Math.round((parent.width - width) / 2)
162
+ y: vector ? Theme.spacing.hairline : Math.round((parent.height - height) / 2)
163
+ width: vector ? boxWidth : implicitWidth * fit
164
+ height: vector ? boxHeight : implicitHeight * fit
165
+ visible: root.thumbShown && !playerLoader.visible && !(gifLoader.item && gifLoader.item.ready)
166
+ // Owned by root.applyDecodeTarget, never bound: a bound url and a bound
167
+ // ceiling land in separate passes and each pass reloads the standing file.
168
+ source: ""
169
+ fillMode: vector ? Image.PreserveAspectFit : Image.Stretch
170
+ // The fallback is the camera file itself, whose EXIF turn Qt applies only when asked.
171
+ autoTransform: true
172
+ asynchronous: true
173
+ cache: false
174
+ Component.onCompleted: root.applyDecodeTarget()
175
+ }
176
+
177
+ // An animated GIF moves only after its still frame is drawn, and not while the column is hidden or covered; the still stays until the first moving frame is ready.
178
+ Loader {
179
+ id: gifLoader
180
+ x: frameThumb.x
181
+ y: frameThumb.y
182
+ width: frameThumb.width
183
+ height: frameThumb.height
184
+ active: root.previewState === Facts.IMAGE && root.meta !== null && root.meta.frames > 1
185
+ && /\.gif$/i.test(root.path) && frameThumb.status === Image.Ready
186
+ source: "PreviewAnimation.qml"
187
+ onLoaded: {
188
+ item.path = Qt.binding(function () { return root.path })
189
+ item.shown = Qt.binding(function () { return root.visible && !root.overlayOpen })
190
+ }
191
+ }
192
+
193
+ // The player, in the frame it paints into; built by the first press of play and not before, and by source rather than type, because QtMultimedia costs 20 MB on import alone.
194
+ Loader {
195
+ id: playerLoader
196
+ anchors.fill: parent
197
+ anchors.margins: Theme.spacing.hairline
198
+ active: root.wantsPlayback && root.playerAllowed
199
+ visible: active && root.previewState === Facts.VIDEO
200
+ source: "PreviewMedia.qml"
201
+ onLoaded: {
202
+ item.path = Qt.binding(function () { return root.path })
203
+ item.kind = Qt.binding(function () {
204
+ return root.previewState === Facts.VIDEO ? "video" : "audio"
205
+ })
206
+ item.letterbox = Qt.binding(function () { return Glass.on ? "transparent" : Theme.color.background })
207
+ // It exists because play was pressed, so it starts.
208
+ item.autoStart = true
209
+ }
210
+ }
211
+
212
+ // The kind's mark, and the one line saying why it is standing in. A frame with neither is
213
+ // the blank-frame defect: an evicted cache file drew a bordered empty box and said nothing.
214
+ Column {
215
+ anchors.centerIn: parent
216
+ spacing: Theme.spacing.gap
217
+ // Match the thumbnail: the video surface owns the frame once opened,
218
+ // including pause/seek, so a missing poster must not cover its pixels.
219
+ visible: !root.thumbShown && !playerLoader.visible && root.glyphState()
220
+
221
+ Flea.Glyph {
222
+ anchors.horizontalCenter: parent.horizontalCenter
223
+ // A kind standing in for a missing thumbnail is a pane state, not a row mark: PreviewColumn.dc.html draws 40 on its Video tile.
224
+ maxSize: Theme.stateMarkSize
225
+ width: Theme.stateMarkSize
226
+ height: Theme.stateMarkSize
227
+ name: root.frameGlyph()
228
+ // A symlink takes the cyan role the row list already gives it; everything else stays muted.
229
+ color: root.previewState === Facts.SYMLINK ? Theme.color.symlink : Theme.color.mutedFrame
230
+ opacity: 0.7
231
+ }
232
+
233
+ Text {
234
+ anchors.horizontalCenter: parent.horizontalCenter
235
+ visible: root.frameNote().length > 0
236
+ text: root.frameNote()
237
+ color: Theme.color.muted
238
+ font.family: Theme.font.family
239
+ font.pixelSize: Theme.font.caption
240
+ textFormat: Text.PlainText
241
+ }
242
+ }
243
+
244
+ // A multi-selection is a count, so the frame stacks the kinds it holds rather than
245
+ // picking one of them; the front mark is the kind the Kinds row below names first.
246
+ Flea.KindStack {
247
+ anchors.centerIn: parent
248
+ visible: root.previewState === Facts.MULTI && root.multiMarks.length > 0
249
+ marks: root.multiMarks
250
+ }
251
+
252
+ // The file's own first lines, which is the frame's whole content for text and code.
253
+ Flea.PreviewLines {
254
+ id: lines
255
+ anchors.fill: parent
256
+ anchors.margins: Theme.spacing.hairline
257
+ visible: (root.previewState === Facts.TEXT || root.previewState === Facts.CODE) && !root.isDocumentRow
258
+ active: root.visible && !root.manualHold && (root.rowState === Facts.TEXT || root.rowState === Facts.CODE) && !root.isDocumentRow
259
+ path: root.path
260
+ size: root.row ? root.row.s : 0
261
+ maxBytes: root.textLimit
262
+ truncate: root.truncateText
263
+ backend: root.pane ? root.pane.backend : null
264
+ numbered: root.previewState === Facts.CODE
265
+ }
266
+ // The document body flows tall with no toggle; a file-path Loader compiles it only when needed.
267
+ Loader {
268
+ id: markdownLoader
269
+ anchors.fill: parent
270
+ anchors.margins: Theme.spacing.hairline
271
+ active: root.markdownActive
272
+ visible: root.isDocumentRow && (!root.isHtmlRow || root.selectionCount <= 1)
273
+ source: root.isHtmlRow ? "PreviewHtml.qml" : "PreviewMarkdown.qml"
274
+ onLoaded: {
275
+ item.path = Qt.binding(function () { return root.path })
276
+ item.size = Qt.binding(function () { return root.row ? root.row.s : 0 })
277
+ item.maxBytes = Qt.binding(function () { return root.isOfficeRow ? Kinds.OFFICE_LIMIT : root.textLimit })
278
+ item.active = Qt.binding(function () { return root.markdownActive })
279
+ item.truncate = Qt.binding(function () { return root.truncateText })
280
+ item.compact = true
281
+ item.externalScrollBars = true
282
+ }
283
+ }
284
+ // The document reader takes the pane's backend once loaded, so Source and Markdown fences colour through the engine.
285
+ Binding {
286
+ target: markdownLoader.item
287
+ property: "backend"
288
+ value: root.pane ? root.pane.backend : null
289
+ when: markdownLoader.status === Loader.Ready
290
+ }
291
+ // The PDF's pages, one under another at the frame's width; QtPdf is reached only through this Loader, so a folder with no PDF never opens one.
292
+ Flickable {
293
+ id: pdfFlick
294
+ anchors.fill: parent
295
+ anchors.margins: Theme.spacing.hairline
296
+ visible: root.previewState === Facts.PDF
297
+ clip: true
298
+ contentWidth: width
299
+ contentHeight: pdfLoader.height
300
+ flickableDirection: Flickable.VerticalFlick
301
+ boundsBehavior: Flickable.StopAtBounds
302
+ Flea.FastScrollHandler { flickable: pdfFlick }
303
+ Flea.ViewportScrollBars { parent: pdfFlick; flickable: pdfFlick }
304
+ Loader {
305
+ id: pdfLoader
306
+ width: pdfFlick.width
307
+ height: item ? item.stackHeight : 0
308
+ active: root.visible && !root.manualHold && root.rowState === Facts.PDF
309
+ source: "PreviewPdf.qml"
310
+ onLoaded: {
311
+ item.continuous = true
312
+ item.path = Qt.binding(function () { return root.path })
313
+ item.viewport = pdfFlick
314
+ item.active = true
315
+ // A document on a hangable class loads from the backend's fetched copy.
316
+ item.backend = Qt.binding(function () { return root.pane ? root.pane.backend : null })
317
+ item.fetchFirst = Qt.binding(function () { return root.pane ? ExtThumbs.present(root.pane.storageClass) : false })
318
+ item.viewerSlot = "column"
319
+ }
320
+ }
321
+ }
322
+
323
+ // The canvas's Archive tile: the first entries by name, then the count it could not show.
324
+ Flea.PreviewArchive {
325
+ id: archivePane
326
+ anchors.fill: parent
327
+ anchors.margins: Theme.spacing.gap
328
+ visible: root.previewState === Facts.ARCHIVE && root.meta !== null
329
+ meta: root.meta
330
+ path: root.path
331
+ pane: root.pane
332
+ }
333
+
334
+ Flea.LoadingState {
335
+ anchors.fill: parent
336
+ visible: root.previewState === Facts.LOADING
337
+ heldOff: root.loadingHeldOff
338
+ }
339
+
340
+ // The one sentence an error is, in the theme's error role; the facts below still show. An office file's
341
+ // embedded thumbnail is the frame's own picture, so Unsupported says "no preview" only when there is none.
342
+ Column {
343
+ anchors.centerIn: parent
344
+ visible: false // Unavailable previews must not cover the content.
345
+ spacing: Theme.spacing.gap
346
+
347
+ Flea.Glyph {
348
+ anchors.horizontalCenter: parent.horizontalCenter
349
+ // A failure mark stands alone, so it takes the pane-state ceiling; the board draws 32 here and 36 for unsupported, and 40 is the one token for both.
350
+ maxSize: Theme.stateMarkSize
351
+ width: Theme.stateMarkSize
352
+ height: Theme.stateMarkSize
353
+ name: root.previewState === Facts.ERROR ? "alert" : "file"
354
+ color: root.previewState === Facts.ERROR ? Theme.color.error : Theme.color.mutedFrame
355
+ }
356
+
357
+ Text {
358
+ anchors.horizontalCenter: parent.horizontalCenter
359
+ text: root.previewState === Facts.ERROR ? root.failure : "no preview"
360
+ color: root.previewState === Facts.ERROR ? Theme.color.foreground : Theme.color.muted
361
+ font.family: Theme.font.family
362
+ font.pixelSize: Theme.font.caption
363
+ textFormat: Text.PlainText
364
+ }
365
+ }
366
+ }
367
+
368
+ // A media file adds the transport strip under the frame, which is what the canvas draws on
369
+ // its Video and Audio tiles. QtMultimedia is reached only through this Loader, on demand.
370
+ Loader {
371
+ id: mediaLoader
372
+ width: parent.width
373
+ height: active ? Theme.chromeHeight : 0
374
+ active: root.visible && (root.previewState === Facts.VIDEO || root.previewState === Facts.AUDIO)
375
+ sourceComponent: mediaTransport
376
+ }
377
+
378
+ // corner: a filename is arbitrary text, so PlainText, the same rule every name on this surface follows.
379
+ Text {
380
+ id: nameText
381
+ width: parent.width
382
+ text: root.nameText()
383
+ color: Theme.color.foreground
384
+ font.family: Theme.font.family
385
+ font.pixelSize: Theme.font.body
386
+ textFormat: Text.PlainText
387
+ elide: Text.ElideRight
388
+ }
389
+
390
+ Flea.PreviewFacts {
391
+ id: facts
392
+ width: parent.width
393
+ compact: root.tallRow && ViewState.previewFacts === "compact"
394
+ line: Facts.compactLine(root.rowState, root.row, root.meta, root.kindName, root.factExtra)
395
+ rows: root.factRows
396
+ }
397
+ }
398
+
399
+ Component {
400
+ id: mediaTransport
401
+
402
+ Item {
403
+ id: transport
404
+ readonly property bool playing: playerLoader.item ? playerLoader.item.status === "playing" : false
405
+ readonly property real position: playerLoader.item ? playerLoader.item.position : 0
406
+ readonly property var strip: strip
407
+
408
+ // The player is playerLoader in the frame above; the probe's duration gives the strip a scale until it exists.
409
+ Flea.MediaStrip {
410
+ id: strip
411
+ anchors.fill: parent
412
+ playing: transport.playing
413
+ position: transport.position
414
+ duration: transport.position > 0 && playerLoader.item && playerLoader.item.duration > 0
415
+ ? playerLoader.item.duration
416
+ : (root.meta && root.meta.durationMs ? root.meta.durationMs : 0)
417
+ onToggled: {
418
+ if (!root.wantsPlayback)
419
+ root.wantsPlayback = true
420
+ else if (playerLoader.item)
421
+ playerLoader.item.togglePlay()
422
+ }
423
+ onSeeked: function (ms) { if (playerLoader.item) playerLoader.item.seekTo(ms) }
424
+ }
425
+ }
426
+ }
427
+
428
+ Flea.PreviewScroll {
429
+ id: scrolling
430
+ column: root
431
+ }
432
+
433
+ function pageBy(direction) {
434
+ if (root.rowState === Facts.PDF) {
435
+ if (!root.overlayOpen && !root.manualHold && !root.pending)
436
+ PreviewKeys.pageViewport(pdfFlick, direction)
437
+ } else scrolling.pageBy(direction)
438
+ }
439
+ // The page under the frame's top, read back over IPC too, and the turn that scrolls to the next or previous one.
440
+ function pdfPage() { return pdfLoader.item ? pdfLoader.item.page : 0 }
441
+ function turnPage(delta) { if (pdfLoader.item) pdfLoader.item.turn(delta) }
442
+ function toggleExpand() { root.expandRequested() }
443
+ function scrollPage(delta) { scrolling.scrollPage(delta, pdfFlick) }
444
+ // Whether a PdfDocument exists at all, which is what makes the Loader worth having.
445
+ function pdfLoaded() { return pdfLoader.item !== null }
446
+ function pdfLanded() { return pdfLoader.item ? pdfLoader.item.landedPages() : [] }
447
+
448
+ // For the geometry gates: the box of the page under the frame's top, or of page index, null until the document below built it.
449
+ function pdfPageItem(index) { return pdfLoader.item ? pdfLoader.item.pageSlot(index === undefined ? pdfLoader.item.page : index) : null }
450
+ // Read back through shell.qml's IPC so a test can prove the transport plays and seeks.
451
+ function mediaPlaying() { return mediaLoader.item ? mediaLoader.item.playing : false }
452
+ function mediaPosition() { return mediaLoader.item ? mediaLoader.item.position : 0 }
453
+ function mediaStripItem() { return mediaLoader.item ? mediaLoader.item.strip : null }
454
+ // Whether a player object exists at all, for the teardown check; playing false alone would mask one that survived.
455
+ function playerLoaded() { return playerLoader.item !== null }
456
+ // What the text, archive and failure surfaces actually draw, for ui/Ipc.qml: the lines, the member names, the sentence.
457
+ function textLines() { return lines.tooLarge ? "too large" : lines.lines.join("|") }
458
+ // Sample input: "# Notes\n###\ntext" reads "Notes\n\ntext"; source view returns the bytes.
459
+ function markdownText() {
460
+ if (!root.isMarkdownRow || !markdown) return ""
461
+ var body = markdown.rawText || ""
462
+ if (markdown.shownView === "source") return body
463
+ var out = body.split("\n")
464
+ for (var i = 0; i < out.length; i++) {
465
+ var head = /^#{1,6}\s/.exec(out[i])
466
+ if (head !== null) out[i] = out[i].slice(head[0].length)
467
+ else if (/^#{1,6}$/.test(out[i])) out[i] = ""
468
+ }
469
+ return out.join("\n")
470
+ }
471
+ readonly property bool textLoading: scrolling.loading
472
+ function archiveNames() { return root.meta && root.meta.names ? root.meta.names.map(function (e) { return e.n }).join("|") : "" }
473
+ function failureText() { return root.failure }
474
+ function toggleFacts() { ViewState.changeKey("previewFacts", ViewState.previewFacts === "compact" ? "full" : "compact") }
475
+
476
+ // The two whole sentences a multi-selection names its count with, one per count, each filled by Format.fill.
477
+ readonly property var selectedWords: ({ one: "%1 item selected", many: "%1 items selected" })
478
+ // A multi-selection describes a count, not a file, so it names the count instead of a name.
479
+ function nameText() {
480
+ if (root.previewState === Facts.MULTI)
481
+ return Format.fill(root.selectionCount === 1 ? root.selectedWords.one : root.selectedWords.many, root.selectionCount)
482
+ return root.row ? root.row.n : ""
483
+ }
484
+
485
+ // One rule for the whole frame: a state that draws its own content takes the mark away, and
486
+ // gives it back the moment its own reader has nothing on screen. Error, unsupported and loading
487
+ // draw a mark of their own, so they never come back here.
488
+ function glyphState() {
489
+ switch (root.previewState) {
490
+ case Facts.ERROR:
491
+ case Facts.UNSUPPORTED:
492
+ case Facts.LOADING:
493
+ return false
494
+ case Facts.PDF:
495
+ return !root.pdfDrawn
496
+ case Facts.TEXT:
497
+ return root.isDocumentRow ? (markdown ? markdown.blank : false) : lines.blank
498
+ case Facts.CODE:
499
+ return root.isDocumentRow ? (markdown ? markdown.blank : false) : lines.blank
500
+ case Facts.ARCHIVE:
501
+ return root.meta === null
502
+ case Facts.MULTI:
503
+ return root.multiMarks.length === 0
504
+ }
505
+ return true
506
+ }
507
+
508
+ // The cache file while there is one, then the image itself once the backend says none is coming.
509
+ // A held frame never decodes the original: its cache entry still shows, nothing else does.
510
+ function frameSource() {
511
+ if (!root.visible) return ""
512
+ if (root.thumb.length > 0)
513
+ return Format.fileUri(root.thumb)
514
+ if (!root.manualHold && root.noThumbComing && root.previewState === Facts.IMAGE && root.path.length > 0 && !root.originalRefused)
515
+ return Format.fileUri(root.path)
516
+ return ""
517
+ }
518
+
519
+ // One binding for the whole decode request: url and ceiling change in one pass, zero is Qt unbounded.
520
+ readonly property var decodeTarget: ({
521
+ url: root.frameSource(),
522
+ w: root.thumb.length > 0 ? 0 : Math.max(1, Math.round(root.turned ? frameThumb.boxHeight : frameThumb.boxWidth)),
523
+ h: root.thumb.length > 0 ? 0 : Math.max(1, Math.round(root.turned ? frameThumb.boxWidth : frameThumb.boxHeight))
524
+ })
525
+ onDecodeTargetChanged: root.applyDecodeTarget()
526
+
527
+ // Blank first, then ceiling, then url, so the three never land in separate passes.
528
+ // A request that changed nothing is skipped, so a relayout over a cache file loads nothing.
529
+ function applyDecodeTarget() {
530
+ var t = root.decodeTarget
531
+ if (String(frameThumb.source) === String(t.url)
532
+ && frameThumb.sourceSize.width === t.w && frameThumb.sourceSize.height === t.h)
533
+ return
534
+ frameThumb.source = ""
535
+ frameThumb.sourceSize.width = t.w
536
+ frameThumb.sourceSize.height = t.h
537
+ frameThumb.source = t.url
538
+ }
539
+
540
+ // Why the frame is showing a mark instead of the thing it meant to draw. Empty for every state
541
+ // whose mark is simply what it draws, so the line only ever appears when something went wrong.
542
+ function frameNote() {
543
+ return root.manualHold ? KeyName.hinted("%1 loads it", "loadPreview") : ""
544
+ }
545
+
546
+ function frameGlyph() {
547
+ if (root.previewState === Facts.SYMLINK)
548
+ return "symlink"
549
+ if (root.previewState === Facts.MULTI)
550
+ return "file"
551
+ return root.row ? Icons.glyphForRow(root.row.i, root.row.p) : "file"
552
+ }
553
+ }