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,456 @@
1
+ import QtQuick
2
+ import qs.Commons
3
+ import "." as Flea
4
+ import "js/Convert.js" as Convert
5
+ import "js/Format.js" as Format
6
+
7
+ // The one popup in the whole design. Every other operation answers in the status bar; this one asks two questions first, so it is the exception the operations design names rather than a pattern.
8
+ Item {
9
+ id: root
10
+
11
+ property bool opened: false
12
+ // The card's title, for ui/Ipc.qml: a driven click on it proves the card swallows what its controls do not.
13
+ readonly property alias titleItem: title
14
+ property string name: ""
15
+ property Item focusHolder: null
16
+ property var owner: null
17
+ property var source: null
18
+ property int serial: 0
19
+ property int requestId: 0
20
+ property int operationId: 0
21
+ property bool checking: false
22
+ property bool checkAgain: false
23
+ property bool busy: false
24
+ property bool unavailable: false
25
+ property bool collision: false
26
+ property string errorText: ""
27
+ property int focusPart: 0
28
+
29
+ // The format row that starts picked is never the one the file already is.
30
+ property string format: ""
31
+ property bool strip: false
32
+ property int cursor: 0
33
+ // Where a row or the ground last saw the pointer, -1 since opening, so a row built under a resting pointer never takes the cursor.
34
+ property point pointerGlobal: Qt.point(-1, -1)
35
+
36
+ signal accepted(var source, string format, bool strip, int requestId)
37
+
38
+ // The card title, filled by Format.fill.
39
+ readonly property string titleWord: "Convert %1"
40
+ readonly property var formats: Convert.FORMATS
41
+ readonly property string outputPath: root.source ? Convert.destination(root.source, root.format) : ""
42
+ readonly property bool editable: !root.busy && !root.unavailable
43
+ readonly property bool canConvert: root.opened && root.editable && !root.checking && !root.collision && !root.errorText
44
+ readonly property var cancelItem: cancelButton
45
+ readonly property var submitItem: convertButton
46
+ readonly property var metadataItem: metadata
47
+ readonly property var outputItem: output
48
+ readonly property var bodyItem: body
49
+ function formatItem(index) { return formatRows.itemAt(index) }
50
+ // What each row prints. The canvas draws JPEG, WebP and AVIF, which is neither the extension
51
+ // nor a plain upper-casing of it, so the wording is a table and not a rule.
52
+ readonly property var formatLabels: ({
53
+ jpg: "JPEG", png: "PNG", webp: "WebP", avif: "AVIF", heic: "HEIC", tiff: "TIFF", bmp: "BMP"
54
+ })
55
+ // The canvas draws this popup at 300 design pixels wide.
56
+ readonly property int dialogWidth: 300
57
+ readonly property int clampMargin: 8
58
+ // var, not Item: BorderSurface is a qs.Ui type qmllint cannot resolve, and Item would read as incompatible.
59
+ readonly property var cardItem: card
60
+
61
+ anchors.fill: parent
62
+ visible: root.opened || root.opacity > 0
63
+ // Closed means no input, even while the fade-out is still drawn.
64
+ enabled: root.opened
65
+ opacity: 0
66
+ z: 2
67
+
68
+ Flea.Reveal { target: root; shown: root.opened; lift: card }
69
+
70
+ // A codec this box converts to but the canvas does not name still needs a cap, so upper-casing
71
+ // the extension is the fallback rather than an empty row.
72
+ function formatLabel(id) {
73
+ var text = root.formatLabels[id]
74
+ return text !== undefined ? text : String(id).toUpperCase()
75
+ }
76
+
77
+ function open(rowName, holder) {
78
+ if (root.opened || !holder || !holder.convertSource) return
79
+ root.owner = holder
80
+ root.source = Object.assign({}, holder.convertSource)
81
+ root.name = root.source.name
82
+ root.format = Convert.defaultFormat(root.name)
83
+ root.strip = false
84
+ root.cursor = root.formats.indexOf(root.format)
85
+ root.pointerGlobal = Qt.point(-1, -1)
86
+ root.focusHolder = holder.listArea
87
+ root.errorText = ""
88
+ root.collision = false
89
+ root.busy = false
90
+ root.unavailable = false
91
+ root.checking = false
92
+ root.checkAgain = false
93
+ root.focusPart = 0
94
+ root.opened = true
95
+ body.contentY = 0
96
+ root.formatItem(root.cursor).forceActiveFocus()
97
+ root.probe()
98
+ }
99
+
100
+ function close() {
101
+ if (!root.opened || root.busy)
102
+ return
103
+ root.opened = false
104
+ if (root.focusHolder)
105
+ root.focusHolder.forceActiveFocus()
106
+ }
107
+
108
+ function commit() {
109
+ if (!root.canConvert) return
110
+ keys.forceActiveFocus()
111
+ root.busy = true
112
+ root.operationId = 0
113
+ root.requestId = ++root.serial
114
+ root.accepted(root.source, root.format, root.strip, root.requestId)
115
+ }
116
+
117
+ function probe() {
118
+ if (!root.opened || !root.editable) return
119
+ if (root.checking) { root.checkAgain = true; return }
120
+ root.checking = true
121
+ root.errorText = ""
122
+ root.collision = false
123
+ root.requestId = ++root.serial
124
+ root.owner.backend.convertImage(root.source.path, root.outputPath, root.strip, root.source.menuId, root.requestId, true)
125
+ }
126
+
127
+ function chooseFormat(index) {
128
+ if (!root.editable) return
129
+ root.focusPart = 0
130
+ root.cursor = Math.max(0, Math.min(root.formats.length - 1, index))
131
+ var next = root.formats[root.cursor]
132
+ if (root.format !== next || root.errorText) {
133
+ root.format = next
134
+ root.probe()
135
+ }
136
+ body.reveal(root.formatItem(root.cursor))
137
+ root.formatItem(root.cursor).forceActiveFocus()
138
+ }
139
+
140
+ function stepFocus(back) {
141
+ if (root.busy) { keys.forceActiveFocus(); return }
142
+ var parts = root.unavailable ? [2] : root.canConvert ? [0, 1, 2, 3] : [0, 1, 2]
143
+ var at = parts.indexOf(root.focusPart)
144
+ root.focusPart = parts[(at + (back ? parts.length - 1 : 1)) % parts.length]
145
+ var item = [root.formatItem(root.cursor), metadata, cancelButton, convertButton][root.focusPart]
146
+ item.forceActiveFocus()
147
+ body.reveal(item)
148
+ }
149
+
150
+ Connections {
151
+ target: root.owner ? root.owner.backend : null
152
+ function onConvertChecked(message) {
153
+ if (!root.opened || root.unavailable || !Convert.matchesReply(root.source, root.requestId, message)) return
154
+ root.checking = false
155
+ if (root.checkAgain || message.path !== root.outputPath) { root.checkAgain = false; root.probe(); return }
156
+ root.collision = message.collision === true
157
+ root.errorText = message.ok && !root.collision ? "" : message.error
158
+ }
159
+ function onConvertStarted(id, requestId, source) {
160
+ if (root.busy && Convert.matchesReply(root.source, root.requestId, {requestId: requestId, source: source}))
161
+ root.operationId = id
162
+ }
163
+ function onConvertDone(id, ok, path, err, requestId, source, collision) {
164
+ if (!root.opened || !root.busy || !Convert.matchesReply(root.source, root.requestId, {requestId: requestId, source: source})
165
+ || (root.operationId ? id !== root.operationId : ok)) return
166
+ root.busy = false
167
+ root.collision = collision
168
+ root.errorText = err
169
+ if (ok) root.close()
170
+ else root.formatItem(root.cursor).forceActiveFocus()
171
+ }
172
+ function onFailed(where, input, message, mode) {
173
+ if (!root.opened || root.unavailable || (where !== "backend" && where !== "read")) return
174
+ var pending = root.busy
175
+ root.unavailable = true
176
+ root.busy = false
177
+ root.checking = false
178
+ root.checkAgain = false
179
+ root.focusPart = 2
180
+ cancelButton.forceActiveFocus()
181
+ root.errorText = pending
182
+ ? "Flea stopped responding, so the conversion may not have finished. Check the converted file."
183
+ : "Flea stopped responding. Reopen Flea, then convert again."
184
+ }
185
+ }
186
+
187
+ // A dimmed ground, and a click on it is a cancel, the same shape the network dialog already uses.
188
+ Rectangle {
189
+ anchors.fill: parent
190
+ color: Theme.color.background
191
+ opacity: 0.5
192
+
193
+ MouseArea {
194
+ id: ground
195
+ anchors.fill: parent
196
+ acceptedButtons: Qt.LeftButton | Qt.RightButton
197
+ hoverEnabled: true
198
+ onEntered: root.pointerGlobal = ground.mapToItem(null, ground.mouseX, ground.mouseY)
199
+ onPositionChanged: function (mouse) { root.pointerGlobal = ground.mapToItem(null, mouse.x, mouse.y) }
200
+ onClicked: root.close()
201
+ onWheel: function (wheel) { wheel.accepted = true }
202
+ }
203
+ }
204
+
205
+ Rectangle {
206
+ id: card
207
+ x: Theme.cardOrigin(root.width, width)
208
+ y: Theme.cardOrigin(root.height, height)
209
+ width: Theme.cardSpan(Theme.space(root.dialogWidth) * Theme.dialogWidthRatio, root.width - 2 * root.clampMargin)
210
+ // Clamped to the window; the body scrolls whatever the clamp cut, see ui/CardScroll.qml.
211
+ height: Theme.cardSpan(body.wanted + 2 * Theme.spacing.rowPaddingX, root.height - 2 * root.clampMargin)
212
+ color: Theme.color.surface
213
+ border.width: Theme.spacing.hairline
214
+ border.color: Theme.color.mutedFrame
215
+ radius: Style.cornerRadius
216
+
217
+ // The strip toggle's handler takes a passive grab, so without this sink its press fell
218
+ // through the card to the ground below, which closed the dialog on release.
219
+ MouseArea {
220
+ id: cardSink
221
+ anchors.fill: parent
222
+ acceptedButtons: Qt.LeftButton | Qt.RightButton
223
+ hoverEnabled: true
224
+ onEntered: root.pointerGlobal = cardSink.mapToItem(null, cardSink.mouseX, cardSink.mouseY)
225
+ onPositionChanged: function (mouse) { root.pointerGlobal = cardSink.mapToItem(null, mouse.x, mouse.y) }
226
+ onClicked: {}
227
+ onWheel: function (wheel) { wheel.accepted = true }
228
+ }
229
+
230
+ Flea.CardFrame {
231
+ id: body
232
+ bleedY: Theme.focusClearance
233
+ anchors.fill: parent
234
+ anchors.topMargin: Theme.spacing.rowPaddingX - Theme.focusClearance
235
+ anchors.bottomMargin: Theme.spacing.rowPaddingX - Theme.focusClearance
236
+ spacing: Theme.spacing.gap / 2
237
+
238
+ title: Item {
239
+ id: title
240
+ width: parent.width
241
+ height: header.implicitHeight + Theme.spacing.gap
242
+
243
+ Flea.DialogTitle {
244
+ id: header
245
+ anchors.left: parent.left
246
+ anchors.right: parent.right
247
+ anchors.margins: Theme.spacing.rowPaddingX
248
+ text: Format.fill(root.titleWord, root.name)
249
+ elide: Text.ElideMiddle
250
+ }
251
+
252
+ Rectangle {
253
+ anchors.bottom: parent.bottom
254
+ width: parent.width
255
+ height: Theme.spacing.hairline
256
+ color: Theme.color.mutedFrame
257
+ opacity: 0.4
258
+ }
259
+ }
260
+
261
+ buttons: Item {
262
+ width: parent.width
263
+ height: Theme.spacing.gap + Math.max(cancelButton.implicitHeight, convertButton.implicitHeight)
264
+ Row {
265
+ anchors.bottom: parent.bottom
266
+ anchors.right: parent.right
267
+ anchors.rightMargin: Theme.spacing.rowPaddingX
268
+ spacing: Theme.spacing.gap
269
+
270
+ Flea.DialogButton {
271
+ id: cancelButton
272
+ label: "Cancel"
273
+ focused: root.focusPart === 2
274
+ available: !root.busy
275
+ enabled: available
276
+ Keys.forwardTo: [keys]
277
+ onActivated: root.close()
278
+ }
279
+
280
+ Flea.DialogButton {
281
+ id: convertButton
282
+ label: "Convert"
283
+ primary: true
284
+ focused: root.focusPart === 3
285
+ available: root.canConvert
286
+ enabled: available
287
+ Keys.forwardTo: [keys]
288
+ onActivated: root.commit()
289
+ }
290
+ }
291
+ }
292
+
293
+ Column {
294
+ width: parent.width
295
+ spacing: Theme.spacing.gap / 2
296
+
297
+ Repeater {
298
+ id: formatRows
299
+ model: root.formats
300
+ delegate: Flea.MenuRow {
301
+ required property string modelData
302
+ required property int index
303
+ width: body.holderWidth
304
+ enabled: root.editable
305
+ entry: ({ label: root.formatLabel(modelData), action: modelData, glyph: "image",
306
+ labelColor: Theme.color.foreground, disabled: !root.editable })
307
+ picked: root.format === modelData
308
+ current: root.focusPart === 0 && root.cursor === index
309
+ Accessible.role: Accessible.RadioButton
310
+ Accessible.name: root.formatLabel(modelData)
311
+ Accessible.checkable: true
312
+ Accessible.checked: root.format === modelData
313
+ Keys.forwardTo: [keys]
314
+ Accessible.onPressAction: root.chooseFormat(index)
315
+ lastPointerGlobal: root.pointerGlobal
316
+ onPointerSeen: function (at) { root.pointerGlobal = at }
317
+ onPointerMoved: { root.focusPart = 0; root.cursor = index }
318
+ onActivated: root.chooseFormat(index)
319
+ }
320
+ }
321
+
322
+ Rectangle {
323
+ width: parent.width
324
+ height: Theme.spacing.hairline
325
+ color: Theme.color.mutedFrame
326
+ opacity: 0.4
327
+ }
328
+
329
+ // The rule's checkbox row; Space and a tap toggle it.
330
+ Item {
331
+ id: metadata
332
+ width: parent.width
333
+ height: Theme.rowHeight
334
+ enabled: root.editable
335
+ Accessible.role: Accessible.CheckBox
336
+ Accessible.name: "Remove metadata"
337
+ Accessible.checkable: true
338
+ Accessible.checked: root.strip
339
+ Keys.forwardTo: [keys]
340
+ Accessible.onPressAction: if (root.editable) root.strip = !root.strip
341
+
342
+ Item {
343
+ id: box
344
+ anchors.left: parent.left
345
+ anchors.leftMargin: Theme.spacing.rowPaddingX
346
+ anchors.verticalCenter: parent.verticalCenter
347
+ width: ruleBox.implicitWidth
348
+ height: ruleBox.implicitHeight
349
+
350
+ Flea.CheckBox {
351
+ id: ruleBox
352
+ value: root.strip ? "on" : "off"
353
+ focused: root.focusPart === 1
354
+ available: root.editable
355
+ }
356
+ }
357
+
358
+ Text {
359
+ anchors.left: box.right
360
+ anchors.leftMargin: Theme.spacing.gap
361
+ anchors.verticalCenter: parent.verticalCenter
362
+ // Unchecked by default: a user converting a photo does not expect metadata
363
+ // silently dropped unless they asked for it.
364
+ text: "Remove metadata"
365
+ color: Theme.color.foreground
366
+ font.family: Theme.font.family
367
+ font.pixelSize: Theme.font.body
368
+ textFormat: Text.PlainText
369
+ }
370
+
371
+ TapHandler {
372
+ acceptedButtons: Qt.LeftButton
373
+ gesturePolicy: TapHandler.ReleaseWithinBounds
374
+ onTapped: if (root.editable) { root.focusPart = 1; root.strip = !root.strip; metadata.forceActiveFocus() }
375
+ }
376
+ }
377
+
378
+ Text {
379
+ id: output
380
+ x: Theme.spacing.rowPaddingX
381
+ width: parent.width - 2 * Theme.spacing.rowPaddingX
382
+ topPadding: 2 * Theme.spacing.hairline
383
+ bottomPadding: 2 * Theme.spacing.hairline
384
+ text: "Output: " + root.outputPath
385
+ color: Theme.color.foreground
386
+ font.family: Theme.font.family
387
+ font.pixelSize: Theme.font.caption
388
+ textFormat: Text.PlainText
389
+ wrapMode: Text.WrapAnywhere
390
+ }
391
+
392
+ // The status slot is always laid out, two caption lines tall (the network slot's rowHeight) inside its padding, so rest, busy and a short error keep one card height; only a longer error grows it.
393
+ Text {
394
+ x: Theme.spacing.rowPaddingX
395
+ width: parent.width - 2 * Theme.spacing.rowPaddingX
396
+ height: Math.max(Theme.rowHeight + topPadding + bottomPadding, implicitHeight)
397
+ topPadding: 2 * Theme.spacing.hairline
398
+ bottomPadding: 2 * Theme.spacing.hairline
399
+ text: root.busy ? "Converting…" : root.errorText
400
+ color: root.busy ? Theme.color.muted : Theme.color.errorOnSurface
401
+ font { family: Theme.font.family; pixelSize: Theme.font.caption }
402
+ textFormat: Text.PlainText
403
+ wrapMode: Text.Wrap
404
+ }
405
+
406
+ Text {
407
+ x: Theme.spacing.rowPaddingX
408
+ width: parent.width - 2 * Theme.spacing.rowPaddingX
409
+ topPadding: 2 * Theme.spacing.hairline
410
+ bottomPadding: 2 * Theme.spacing.hairline
411
+ visible: root.collision
412
+ text: "Choose another format."
413
+ color: Theme.color.foreground
414
+ font { family: Theme.font.family; pixelSize: Theme.font.caption }
415
+ textFormat: Text.PlainText
416
+ wrapMode: Text.Wrap
417
+ }
418
+ }
419
+ }
420
+ }
421
+
422
+ Item {
423
+ id: keys
424
+ anchors.fill: parent
425
+
426
+ Keys.onPressed: function (event) {
427
+ event.accepted = true
428
+ if (event.key === Qt.Key_Escape) { root.close(); event.accepted = true; return }
429
+ if (event.key === Qt.Key_Tab || event.key === Qt.Key_Backtab) {
430
+ root.stepFocus(event.key === Qt.Key_Backtab || (event.modifiers & Qt.ShiftModifier)); return
431
+ }
432
+ if (root.busy) return
433
+ if (root.unavailable) {
434
+ if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter || event.key === Qt.Key_Space) root.close()
435
+ return
436
+ }
437
+ if (event.key === Qt.Key_Down) {
438
+ root.chooseFormat(root.cursor + 1)
439
+ event.accepted = true
440
+ return
441
+ }
442
+ if (event.key === Qt.Key_Up) {
443
+ root.chooseFormat(root.cursor - 1)
444
+ event.accepted = true
445
+ return
446
+ }
447
+ // Space toggles the one checkbox, which is the only other thing this popup asks.
448
+ if (event.key === Qt.Key_Space && root.focusPart < 2) { root.strip = !root.strip; return }
449
+ if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter || event.key === Qt.Key_Space) {
450
+ if (root.focusPart === 2) root.close()
451
+ else if (root.focusPart === 1) root.strip = !root.strip
452
+ else root.commit()
453
+ }
454
+ }
455
+ }
456
+ }
@@ -0,0 +1,7 @@
1
+ import QtQuick
2
+
3
+ // Says WORKER_STARTED under flea.worker (off unless QT_LOGGING_RULES names it), so log checks match Qt 6.11.2's one null connect warning per start.
4
+ WorkerScript {
5
+ property QtObject startLog: LoggingCategory { name: "flea.worker"; defaultLogLevel: LoggingCategory.Warning }
6
+ Component.onCompleted: if (source.toString() !== "") console.info(startLog, "WORKER_STARTED " + source)
7
+ }
package/ui/Crumb.qml ADDED
@@ -0,0 +1,64 @@
1
+ import QtQuick
2
+
3
+ // One piece of a path that a click can land on, the chrome's and a dual pane's alike; keys.toml's "chrome" rows are its contract.
4
+ Text {
5
+ id: crumb
6
+
7
+ required property var modelData
8
+ // What an ancestor reads at rest: muted in the chrome, where only the leaf is lit, and the foreground on a dual pane's path.
9
+ property color restColor: Theme.color.muted
10
+ // ui/ChromeButton.qml's inputLive: the handlers stop while something covers the crumb.
11
+ property bool inputLive: true
12
+ // Drops callout 4: the pane whose collide sends a drop on this crumb, null where crumbs take none.
13
+ property var dropPane: null
14
+ // The hovered ancestor inside the row's drop frame: an accent hairline over the wash, inside the crumb's own advance.
15
+ property bool dropTarget: false
16
+ // Built when a drag first needs it and kept, so no DropArea per crumb stands at startup.
17
+ property var dropArea: null
18
+ // A platform drag sends no hover, so the lift is what builds the target; the first hover builds it too.
19
+ readonly property bool dragLive: crumb.dropPane !== null && crumb.dropPane.dragActive === true
20
+ onDragLiveChanged: if (crumb.dragLive) crumb.armDrop()
21
+
22
+ signal chosen(string path)
23
+ signal editRequested()
24
+
25
+ // corner: a path is arbitrary text, so PlainText, the same rule every filename on this surface follows.
26
+ text: crumb.modelData.text
27
+ color: crumb.dropTarget ? Theme.color.accent
28
+ : crumb.modelData.last || (crumbHover.hovered && !crumb.modelData.elided) ? Theme.color.foreground : crumb.restColor
29
+ font.family: Theme.font.family
30
+ font.pixelSize: Theme.font.caption
31
+ textFormat: Text.PlainText
32
+ verticalAlignment: Text.AlignVCenter
33
+
34
+ function armDrop() {
35
+ if (crumb.dropArea !== null || crumb.dropPane === null)
36
+ return
37
+ var dest = String(crumb.modelData.path || "")
38
+ if (dest.length === 0 || crumb.modelData.last === true)
39
+ return
40
+ var area = Qt.createComponent("CrumbDrop.qml").createObject(crumb,
41
+ { crumb: crumb, pane: crumb.dropPane, dest: dest, label: String(crumb.modelData.text || "") })
42
+ if (area === null)
43
+ return
44
+ crumb.dropArea = area
45
+ }
46
+
47
+ HoverHandler {
48
+ id: crumbHover
49
+ enabled: crumb.inputLive
50
+ cursorShape: crumb.modelData.last || crumb.modelData.elided ? Qt.IBeamCursor : Qt.PointingHandCursor
51
+ onHoveredChanged: if (hovered) crumb.armDrop()
52
+ }
53
+
54
+ // No exclusiveSignals, decided 2026-09-22: the pair held every tap for the whole double-click interval, about 400 ms.
55
+ // The gesture sits on the crumb because a TapHandler on a parent takes the second tap from the child under the pointer.
56
+ TapHandler {
57
+ enabled: crumb.inputLive
58
+ acceptedButtons: Qt.LeftButton
59
+ // The collapsed marker names no directory, so a press on it opens nothing rather than whichever crumb it stands for.
60
+ onSingleTapped: if (!crumb.modelData.last && !crumb.modelData.elided) crumb.chosen(crumb.modelData.path)
61
+ // Only where a tap opens nothing does a double click type the path; on a parent it is two taps.
62
+ onDoubleTapped: if (crumb.modelData.last || crumb.modelData.elided) crumb.editRequested()
63
+ }
64
+ }
@@ -0,0 +1,25 @@
1
+ import QtQuick
2
+ import "." as Flea
3
+ import "js/DropDev.js" as DropDev
4
+
5
+ // One crumb's drop target: the floor's own receiver, naming the crumb, with a frame inside the crumb's own advance so it never reaches the "/" either side.
6
+ Flea.DropInto {
7
+ id: root
8
+
9
+ required property var crumb
10
+ anchors.fill: parent
11
+ enabled: root.crumb.inputLive && root.pane !== null
12
+ refuseLoading: root.pane ? root.pane.listInFlight === true : true
13
+ // A plain drop moves on the source volume and copies across it; this crumb's device is the backend's answer, and an unanswered one copies.
14
+ destDev: DropDev.devFor(root.pane && root.pane.backend ? root.pane.backend.pathDevs : null, root.dest)
15
+ onContainsDragChanged: root.crumb.dropTarget = root.containsDrag
16
+
17
+ Rectangle {
18
+ anchors.fill: parent
19
+ visible: root.containsDrag
20
+ color: Theme.color.accent
21
+ opacity: 0.08
22
+ border.width: Theme.spacing.hairline
23
+ border.color: Theme.color.accent
24
+ }
25
+ }