flea-qml 0.0.0-stage → 0.1.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 (625) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +478 -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 +402 -0
  51. package/src/archiveops.js +697 -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 +129 -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/transfer.js +669 -0
  82. package/src/trash-record.js +41 -0
  83. package/src/trash.js +210 -0
  84. package/src/trashbrowse.js +326 -0
  85. package/src/uistate.js +393 -0
  86. package/src/uistore.js +168 -0
  87. package/src/vendor/LICENSES/Apache-2.0.txt +202 -0
  88. package/src/vendor/LICENSES/MIT-katex-2015.txt +27 -0
  89. package/src/vendor/LICENSES/MIT-katex.txt +21 -0
  90. package/src/vendor/LICENSES/MIT-mermaid.txt +21 -0
  91. package/src/vendor/LICENSES/MIT-pele.txt +40 -0
  92. package/src/vendor/LICENSES/MIT-perseus.txt +18 -0
  93. package/src/vendor/LICENSES/MIT-temml.txt +21 -0
  94. package/src/vendor/pele.js +145 -0
  95. package/src/vendor/temml.mjs +14708 -0
  96. package/src/watch.js +98 -0
  97. package/src/wayland/client.js +109 -0
  98. package/src/wayland/protocol.js +55 -0
  99. package/src/wayland/protocols/ext-data-control-v1.xml +276 -0
  100. package/src/wayland/protocols/wayland.xml +3248 -0
  101. package/src/wayland/protocols/wlr-data-control-unstable-v1.xml +278 -0
  102. package/src/wayland/resource-io.js +6 -0
  103. package/src/wayland/socket-discovery.js +26 -0
  104. package/src/wayland/transport-posix.js +120 -0
  105. package/src/wayland/transport-win32.js +11 -0
  106. package/src/wayland/transport.js +3 -0
  107. package/src/wayland/win32-resources.js +80 -0
  108. package/src/wayland/win32-wire.js +62 -0
  109. package/test/archive.test.js +80 -0
  110. package/test/bench-markdown-scroll.mjs +190 -0
  111. package/test/clip-host.test.js +113 -0
  112. package/test/code-preview.test.js +35 -0
  113. package/test/compare-ui-paths.test.js +24 -0
  114. package/test/compare.test.js +54 -0
  115. package/test/delete-trash.test.js +67 -0
  116. package/test/dirsize.test.js +138 -0
  117. package/test/file-ops.test.js +241 -0
  118. package/test/find-contents.test.js +161 -0
  119. package/test/find-input.test.js +66 -0
  120. package/test/fixtures/pele-parity.json +1006 -0
  121. package/test/highlight-launcher.test.js +35 -0
  122. package/test/html-preview.test.js +22 -0
  123. package/test/input.test.js +15 -0
  124. package/test/keymap.test.js +26 -0
  125. package/test/language-icons.test.js +36 -0
  126. package/test/launcher.test.js +51 -0
  127. package/test/manual-code-scroll.mjs +28 -0
  128. package/test/manual-column-scroll.mjs +24 -0
  129. package/test/manual-compare-ui.mjs +20 -0
  130. package/test/manual-find-status.mjs +37 -0
  131. package/test/manual-html-security.mjs +23 -0
  132. package/test/manual-html-ui.mjs +30 -0
  133. package/test/manual-syntax-preview.mjs +26 -0
  134. package/test/manual-trash-ui.mjs +86 -0
  135. package/test/markdown-diagrams.test.js +93 -0
  136. package/test/markdown-html.test.js +105 -0
  137. package/test/mathml.test.js +92 -0
  138. package/test/menu-transfer.test.js +57 -0
  139. package/test/office-preview.test.js +154 -0
  140. package/test/pele-parity.test.js +28 -0
  141. package/test/places.test.js +134 -0
  142. package/test/preview-keys.test.js +60 -0
  143. package/test/preview-language.test.js +22 -0
  144. package/test/status-filename.test.js +20 -0
  145. package/test/transfer-replace-merge.test.js +187 -0
  146. package/test/trash-address.test.js +23 -0
  147. package/test/trash-view.test.js +37 -0
  148. package/test/trashbrowse.test.js +135 -0
  149. package/ui/AboutFacts.qml +78 -0
  150. package/ui/ArchiveCards.qml +68 -0
  151. package/ui/ArchiveCompressDialog.qml +378 -0
  152. package/ui/ArchivePasswordDialog.qml +257 -0
  153. package/ui/Backend.qml +771 -0
  154. package/ui/BulkOldNames.qml +47 -0
  155. package/ui/BulkRenameDialog.qml +380 -0
  156. package/ui/CardFrame.qml +67 -0
  157. package/ui/CardScroll.qml +79 -0
  158. package/ui/CheckBox.qml +73 -0
  159. package/ui/ChromeBar.qml +360 -0
  160. package/ui/ChromeButton.qml +131 -0
  161. package/ui/ChromeModes.qml +43 -0
  162. package/ui/CodeLines.qml +256 -0
  163. package/ui/CodeRefusal.qml +52 -0
  164. package/ui/CollideConfirm.qml +147 -0
  165. package/ui/CollideHost.qml +167 -0
  166. package/ui/ColumnPane.qml +523 -0
  167. package/ui/ColumnRow.qml +380 -0
  168. package/ui/ColumnsArea.qml +594 -0
  169. package/ui/ColumnsLanding.qml +147 -0
  170. package/ui/CompareView.qml +321 -0
  171. package/ui/ContextMenu.qml +743 -0
  172. package/ui/ConvertDialog.qml +456 -0
  173. package/ui/CountedWorker.qml +7 -0
  174. package/ui/Crumb.qml +64 -0
  175. package/ui/CrumbDrop.qml +25 -0
  176. package/ui/CsvTable.qml +394 -0
  177. package/ui/CursorMark.qml +41 -0
  178. package/ui/DefaultClaim.qml +130 -0
  179. package/ui/DeviceLock.qml +47 -0
  180. package/ui/DeviceMounts.qml +540 -0
  181. package/ui/DialogButton.qml +150 -0
  182. package/ui/DialogField.qml +147 -0
  183. package/ui/DialogHeader.qml +31 -0
  184. package/ui/DialogScrim.qml +20 -0
  185. package/ui/DialogTitle.qml +37 -0
  186. package/ui/Divider.qml +9 -0
  187. package/ui/DropInto.qml +126 -0
  188. package/ui/DropTarget.qml +35 -0
  189. package/ui/DropboxMark.qml +60 -0
  190. package/ui/EmptyState.qml +150 -0
  191. package/ui/EscapeHint.qml +11 -0
  192. package/ui/FactsTable.qml +54 -0
  193. package/ui/FastScrollHandler.qml +476 -0
  194. package/ui/FatNamesConfirm.qml +157 -0
  195. package/ui/Favourites.qml +143 -0
  196. package/ui/FigureService.qml +120 -0
  197. package/ui/FileDrag.qml +267 -0
  198. package/ui/FilterStrip.qml +133 -0
  199. package/ui/FitMetrics.qml +22 -0
  200. package/ui/FlashDriveRows.qml +137 -0
  201. package/ui/FlashHost.qml +72 -0
  202. package/ui/FlashImageRow.qml +104 -0
  203. package/ui/FlashRunner.qml +119 -0
  204. package/ui/FlashStepRow.qml +172 -0
  205. package/ui/FlashStrip.qml +38 -0
  206. package/ui/FlashView.qml +397 -0
  207. package/ui/FleaMark.qml +88 -0
  208. package/ui/FlyoutFade.qml +23 -0
  209. package/ui/FontPane.qml +170 -0
  210. package/ui/Glass.qml +114 -0
  211. package/ui/GlassTagger.qml +59 -0
  212. package/ui/Glyph.qml +64 -0
  213. package/ui/GlyphSolid.qml +22 -0
  214. package/ui/GridArea.qml +664 -0
  215. package/ui/GridTile.qml +325 -0
  216. package/ui/GvfsBridge.qml +164 -0
  217. package/ui/Header.qml +433 -0
  218. package/ui/HoverTimers.qml +39 -0
  219. package/ui/HtmlClip.qml +30 -0
  220. package/ui/HtmlPane.qml +63 -0
  221. package/ui/HyprlandMark.qml +45 -0
  222. package/ui/Ipc.qml +1005 -0
  223. package/ui/IpcControls.qml +7 -0
  224. package/ui/IpcMenuState.qml +48 -0
  225. package/ui/IpcPreviewState.qml +185 -0
  226. package/ui/JumpPath.qml +51 -0
  227. package/ui/KeymapSheet.qml +561 -0
  228. package/ui/KeymapSheetResult.qml +89 -0
  229. package/ui/KindStack.qml +40 -0
  230. package/ui/LangMark.qml +51 -0
  231. package/ui/LangMarkLoader.qml +26 -0
  232. package/ui/List.qml +480 -0
  233. package/ui/LoadingState.qml +54 -0
  234. package/ui/LocalSend.qml +56 -0
  235. package/ui/LocalSendMark.qml +73 -0
  236. package/ui/MarkdownBlockView.qml +311 -0
  237. package/ui/MarkdownBlocks.qml +35 -0
  238. package/ui/MarkdownFigure.qml +254 -0
  239. package/ui/MarkdownImages.qml +72 -0
  240. package/ui/MarkdownList.qml +81 -0
  241. package/ui/MarkdownMathsText.qml +97 -0
  242. package/ui/MarkdownPane.qml +83 -0
  243. package/ui/MarkdownPictures.qml +41 -0
  244. package/ui/MarkdownQuote.qml +52 -0
  245. package/ui/MarkdownRemote.qml +82 -0
  246. package/ui/MarkdownSource.qml +155 -0
  247. package/ui/MarkdownTable.qml +222 -0
  248. package/ui/MarkdownTableScroll.qml +64 -0
  249. package/ui/MarkdownTableWheel.qml +126 -0
  250. package/ui/MarkdownText.qml +87 -0
  251. package/ui/MarkdownWorker.js +132 -0
  252. package/ui/MatchText.qml +99 -0
  253. package/ui/MediaSession.qml +38 -0
  254. package/ui/MediaSound.qml +26 -0
  255. package/ui/MediaStrip.qml +191 -0
  256. package/ui/MediaTrack.qml +36 -0
  257. package/ui/MediaVolume.qml +54 -0
  258. package/ui/MenuActionDialog.qml +396 -0
  259. package/ui/MenuEdgeFade.qml +24 -0
  260. package/ui/MenuHost.qml +227 -0
  261. package/ui/MenuRow.qml +351 -0
  262. package/ui/MountListing.qml +100 -0
  263. package/ui/NetworkDialog.qml +435 -0
  264. package/ui/NetworkForm.qml +426 -0
  265. package/ui/NetworkMounts.qml +913 -0
  266. package/ui/NetworkPlaces.qml +127 -0
  267. package/ui/OpenWithDialog.qml +613 -0
  268. package/ui/Opener.qml +115 -0
  269. package/ui/Pane.qml +1296 -0
  270. package/ui/PaneMenuActions.qml +527 -0
  271. package/ui/PanePath.qml +90 -0
  272. package/ui/PaneRail.qml +239 -0
  273. package/ui/PaneStates.qml +88 -0
  274. package/ui/PaneSwap.qml +339 -0
  275. package/ui/PaneWire.qml +605 -0
  276. package/ui/ParkedWait.qml +9 -0
  277. package/ui/PathEntry.qml +186 -0
  278. package/ui/PathJump.qml +400 -0
  279. package/ui/PdfViewer.qml +297 -0
  280. package/ui/PermissionsDialog.qml +658 -0
  281. package/ui/PermissionsHeadings.qml +31 -0
  282. package/ui/PhoneMounts.qml +67 -0
  283. package/ui/PickerAnswers.qml +75 -0
  284. package/ui/PickerBox.qml +26 -0
  285. package/ui/PickerChrome.qml +295 -0
  286. package/ui/PickerFilter.qml +97 -0
  287. package/ui/PickerGrid.qml +308 -0
  288. package/ui/PickerHeader.qml +28 -0
  289. package/ui/PickerLifecycle.qml +27 -0
  290. package/ui/PickerList.qml +218 -0
  291. package/ui/PickerListing.qml +149 -0
  292. package/ui/PickerPathBar.qml +127 -0
  293. package/ui/PickerPlaces.qml +189 -0
  294. package/ui/PickerRecent.qml +92 -0
  295. package/ui/PickerSave.qml +101 -0
  296. package/ui/PickerSelection.qml +155 -0
  297. package/ui/PickerWindow.qml +846 -0
  298. package/ui/PowerSectorsReader.qml +10 -0
  299. package/ui/PrebuildDriver.qml +146 -0
  300. package/ui/Preview.qml +1004 -0
  301. package/ui/PreviewAnimation.qml +24 -0
  302. package/ui/PreviewArchive.qml +66 -0
  303. package/ui/PreviewColumn.qml +551 -0
  304. package/ui/PreviewEdge.qml +63 -0
  305. package/ui/PreviewFacts.qml +30 -0
  306. package/ui/PreviewFactsLine.qml +34 -0
  307. package/ui/PreviewHtml.qml +233 -0
  308. package/ui/PreviewImage.qml +253 -0
  309. package/ui/PreviewImagePan.qml +13 -0
  310. package/ui/PreviewImageSharp.qml +32 -0
  311. package/ui/PreviewLines.qml +106 -0
  312. package/ui/PreviewMarkdown.qml +706 -0
  313. package/ui/PreviewMedia.qml +250 -0
  314. package/ui/PreviewPdf.qml +482 -0
  315. package/ui/PreviewScroll.qml +201 -0
  316. package/ui/PreviewSwap.qml +335 -0
  317. package/ui/PreviewText.qml +149 -0
  318. package/ui/ProtocolChip.qml +18 -0
  319. package/ui/QuickLookArchive.qml +38 -0
  320. package/ui/QuickLookBar.qml +103 -0
  321. package/ui/QuickLookPrepare.qml +355 -0
  322. package/ui/QuickLookSwap.qml +10 -0
  323. package/ui/QuickLookWarm.qml +65 -0
  324. package/ui/RailDrop.qml +155 -0
  325. package/ui/RailHeading.qml +19 -0
  326. package/ui/RailPlaces.qml +38 -0
  327. package/ui/RailTrashRow.qml +67 -0
  328. package/ui/RenameField.qml +353 -0
  329. package/ui/RendererRetry.qml +11 -0
  330. package/ui/ResizeHandle.qml +52 -0
  331. package/ui/Reveal.qml +54 -0
  332. package/ui/Row.qml +476 -0
  333. package/ui/RowDrag.qml +213 -0
  334. package/ui/RowDropTarget.qml +27 -0
  335. package/ui/RunCard.qml +286 -0
  336. package/ui/Scripts.qml +65 -0
  337. package/ui/SearchStrip.qml +232 -0
  338. package/ui/SelectionBand.qml +140 -0
  339. package/ui/SelectionPreview.qml +370 -0
  340. package/ui/SettingsFavourite.qml +122 -0
  341. package/ui/SettingsGroup.qml +96 -0
  342. package/ui/SettingsHint.qml +12 -0
  343. package/ui/SettingsMetrics.qml +29 -0
  344. package/ui/SettingsPane.qml +178 -0
  345. package/ui/SettingsPanel.qml +547 -0
  346. package/ui/SettingsRail.qml +128 -0
  347. package/ui/SettingsRow.qml +409 -0
  348. package/ui/SettingsRuler.qml +85 -0
  349. package/ui/SettingsSegment.qml +85 -0
  350. package/ui/ShareBrowser.qml +113 -0
  351. package/ui/ShareLink.qml +67 -0
  352. package/ui/ShelfPins.qml +101 -0
  353. package/ui/Sidebar.qml +732 -0
  354. package/ui/SidebarRow.qml +358 -0
  355. package/ui/Spinner.qml +60 -0
  356. package/ui/StableModel.qml +89 -0
  357. package/ui/StateMessage.qml +84 -0
  358. package/ui/StatusBar.qml +512 -0
  359. package/ui/StatusFileName.qml +27 -0
  360. package/ui/TabBar.qml +673 -0
  361. package/ui/TabDragGeometry.qml +60 -0
  362. package/ui/TagMenuMark.qml +52 -0
  363. package/ui/TagRailSection.qml +53 -0
  364. package/ui/TagSlot.qml +40 -0
  365. package/ui/TagState.qml +150 -0
  366. package/ui/TagSwatch.qml +28 -0
  367. package/ui/Taildrop.qml +86 -0
  368. package/ui/TailscaleMark.qml +50 -0
  369. package/ui/Theme.qml +460 -0
  370. package/ui/ThemeColors.qml +43 -0
  371. package/ui/TransferCard.qml +239 -0
  372. package/ui/TrashConfirm.qml +129 -0
  373. package/ui/TrashDropHandler.qml +11 -0
  374. package/ui/TrashHost.qml +202 -0
  375. package/ui/TrashMonitor.qml +30 -0
  376. package/ui/TrashToolbar.qml +19 -0
  377. package/ui/TrashView.qml +492 -0
  378. package/ui/UnlockDialog.qml +450 -0
  379. package/ui/UnlockHost.qml +206 -0
  380. package/ui/UpdateCheck.qml +97 -0
  381. package/ui/UserDirs.qml +25 -0
  382. package/ui/ViewState.qml +565 -0
  383. package/ui/ViewportScrollBar.qml +195 -0
  384. package/ui/ViewportScrollBars.qml +25 -0
  385. package/ui/WebPreview.qml +33 -0
  386. package/ui/WebPreviewView.qml +26 -0
  387. package/ui/WindowBody.qml +827 -0
  388. package/ui/WindowDrag.qml +35 -0
  389. package/ui/boot/Commons/AudioNodes.qml +50 -0
  390. package/ui/boot/Commons/AudioNodesModel.js +96 -0
  391. package/ui/boot/Commons/Border.qml +243 -0
  392. package/ui/boot/Commons/BorderGeometry.js +373 -0
  393. package/ui/boot/Commons/Color.qml +258 -0
  394. package/ui/boot/Commons/I18n.qml +118 -0
  395. package/ui/boot/Commons/InputDevices.qml +112 -0
  396. package/ui/boot/Commons/InputMethodState.qml +38 -0
  397. package/ui/boot/Commons/IpcRegistry.qml +77 -0
  398. package/ui/boot/Commons/Numbers.js +19 -0
  399. package/ui/boot/Commons/Plural.js +91 -0
  400. package/ui/boot/Commons/ShellIpc.qml +12 -0
  401. package/ui/boot/Commons/Style.qml +561 -0
  402. package/ui/boot/Commons/Translations.qml +100 -0
  403. package/ui/boot/Commons/UntypedInput.qml +152 -0
  404. package/ui/boot/Commons/Util.qml +188 -0
  405. package/ui/boot/Commons/qmldir +13 -0
  406. package/ui/boot/LICENSE-omarchy +20 -0
  407. package/ui/boot/Ui/BackgroundMedia.qml +49 -0
  408. package/ui/boot/Ui/BarIconButton.qml +106 -0
  409. package/ui/boot/Ui/BarIconContent.qml +38 -0
  410. package/ui/boot/Ui/BarIndicator.qml +53 -0
  411. package/ui/boot/Ui/BarWidget.qml +50 -0
  412. package/ui/boot/Ui/BorderOverlay.qml +54 -0
  413. package/ui/boot/Ui/BorderSurface.qml +40 -0
  414. package/ui/boot/Ui/Button.qml +224 -0
  415. package/ui/boot/Ui/ButtonGroup.qml +131 -0
  416. package/ui/boot/Ui/ConfirmDialog.qml +134 -0
  417. package/ui/boot/Ui/CursorSurface.qml +42 -0
  418. package/ui/boot/Ui/Dropdown.qml +245 -0
  419. package/ui/boot/Ui/FilterInput.qml +26 -0
  420. package/ui/boot/Ui/IconContentBounds.qml +141 -0
  421. package/ui/boot/Ui/KeyboardPanel.qml +453 -0
  422. package/ui/boot/Ui/MultiSelect.qml +624 -0
  423. package/ui/boot/Ui/NumberField.qml +86 -0
  424. package/ui/boot/Ui/OpticalGlyph.qml +68 -0
  425. package/ui/boot/Ui/OverlayWindow.qml +102 -0
  426. package/ui/boot/Ui/Panel.qml +60 -0
  427. package/ui/boot/Ui/PanelActionButton.qml +105 -0
  428. package/ui/boot/Ui/PanelController.qml +16 -0
  429. package/ui/boot/Ui/PanelHero.qml +112 -0
  430. package/ui/boot/Ui/PanelKeyCatcher.qml +100 -0
  431. package/ui/boot/Ui/PanelSectionHeader.qml +31 -0
  432. package/ui/boot/Ui/PanelSeparator.qml +19 -0
  433. package/ui/boot/Ui/PanelSlider.qml +156 -0
  434. package/ui/boot/Ui/PanelToolTip.qml +50 -0
  435. package/ui/boot/Ui/PluginBarApi.qml +89 -0
  436. package/ui/boot/Ui/PointerMoveGate.qml +54 -0
  437. package/ui/boot/Ui/PopupCard.qml +181 -0
  438. package/ui/boot/Ui/ScreenMoveRemap.qml +43 -0
  439. package/ui/boot/Ui/SearchableDropdown.qml +354 -0
  440. package/ui/boot/Ui/SizedImage.qml +125 -0
  441. package/ui/boot/Ui/SpeedTestOverlay.qml +412 -0
  442. package/ui/boot/Ui/TextField.qml +58 -0
  443. package/ui/boot/Ui/Toggle.qml +118 -0
  444. package/ui/boot/Ui/ToggleSwitch.qml +115 -0
  445. package/ui/boot/Ui/WidgetButton.qml +172 -0
  446. package/ui/boot/Ui/qmldir +41 -0
  447. package/ui/boot/fleatab.qml +50 -0
  448. package/ui/boot/picker.qml +39 -0
  449. package/ui/boot/shell.qml +122 -0
  450. package/ui/boot/tabtearoff.qml +51 -0
  451. package/ui/js/Anchor.js +379 -0
  452. package/ui/js/AnchorHold.js +162 -0
  453. package/ui/js/Archive.js +157 -0
  454. package/ui/js/ArchiveCard.js +44 -0
  455. package/ui/js/ArchiveOps.js +44 -0
  456. package/ui/js/BackReturn.js +118 -0
  457. package/ui/js/BulkRename.js +100 -0
  458. package/ui/js/Buttons.js +54 -0
  459. package/ui/js/ChromeKeys.js +116 -0
  460. package/ui/js/ClipMarks.js +73 -0
  461. package/ui/js/ClipSelection.js +67 -0
  462. package/ui/js/Clipboard.js +179 -0
  463. package/ui/js/Cloud.js +97 -0
  464. package/ui/js/CodeRuns.js +72 -0
  465. package/ui/js/Collide.js +212 -0
  466. package/ui/js/ColumnFit.js +28 -0
  467. package/ui/js/ColumnMenu.js +111 -0
  468. package/ui/js/Columns.js +298 -0
  469. package/ui/js/ColumnsCarry.js +103 -0
  470. package/ui/js/Compare.js +74 -0
  471. package/ui/js/Contrast.js +157 -0
  472. package/ui/js/ControlReader.js +42 -0
  473. package/ui/js/Convert.js +52 -0
  474. package/ui/js/CopyAs.js +52 -0
  475. package/ui/js/Crumbs.js +178 -0
  476. package/ui/js/Csv.js +231 -0
  477. package/ui/js/Density.js +44 -0
  478. package/ui/js/Devices.js +440 -0
  479. package/ui/js/DirSizes.js +180 -0
  480. package/ui/js/Drag.js +364 -0
  481. package/ui/js/DragOut.js +166 -0
  482. package/ui/js/DropDev.js +52 -0
  483. package/ui/js/Dropbox.js +41 -0
  484. package/ui/js/Eject.js +217 -0
  485. package/ui/js/Errors.js +188 -0
  486. package/ui/js/ExtThumbs.js +115 -0
  487. package/ui/js/Facts.js +402 -0
  488. package/ui/js/FigureDate.js +14 -0
  489. package/ui/js/Filter.js +285 -0
  490. package/ui/js/Find.js +46 -0
  491. package/ui/js/Flash.js +184 -0
  492. package/ui/js/FlashCard.js +79 -0
  493. package/ui/js/FlashEndings.js +125 -0
  494. package/ui/js/FlashPane.js +116 -0
  495. package/ui/js/FleaBin.js +12 -0
  496. package/ui/js/Focus.js +502 -0
  497. package/ui/js/FolderSorts.js +108 -0
  498. package/ui/js/FolderViews.js +44 -0
  499. package/ui/js/Format.js +305 -0
  500. package/ui/js/Fuzzy.js +141 -0
  501. package/ui/js/GlassTag.js +72 -0
  502. package/ui/js/Grid.js +33 -0
  503. package/ui/js/GridGeometry.js +90 -0
  504. package/ui/js/GridNames.js +153 -0
  505. package/ui/js/GvfsBridge.js +200 -0
  506. package/ui/js/HostClipboard.js +29 -0
  507. package/ui/js/Icons.js +218 -0
  508. package/ui/js/Input.js +50 -0
  509. package/ui/js/Jump.js +200 -0
  510. package/ui/js/KeyName.js +64 -0
  511. package/ui/js/Keymap.js +401 -0
  512. package/ui/js/Kinds.js +164 -0
  513. package/ui/js/LICENSES/ISC-lucide.txt +43 -0
  514. package/ui/js/LangMarkPaths.js +47 -0
  515. package/ui/js/LangMarks.js +120 -0
  516. package/ui/js/Lists.js +11 -0
  517. package/ui/js/LocalSend.js +39 -0
  518. package/ui/js/LockedMenu.js +63 -0
  519. package/ui/js/MakeDefault.js +186 -0
  520. package/ui/js/MarkBox.js +7 -0
  521. package/ui/js/Markdown.js +119 -0
  522. package/ui/js/MarkdownLists.js +86 -0
  523. package/ui/js/MarkdownMaths.js +58 -0
  524. package/ui/js/MarkdownPictures.js +32 -0
  525. package/ui/js/MarkdownPrepared.js +139 -0
  526. package/ui/js/MarkdownTableFit.js +34 -0
  527. package/ui/js/Marks.js +148 -0
  528. package/ui/js/Marquee.js +96 -0
  529. package/ui/js/Match.js +93 -0
  530. package/ui/js/Material.js +109 -0
  531. package/ui/js/MdBlocks.js +437 -0
  532. package/ui/js/MdBreak.js +71 -0
  533. package/ui/js/MdChunks.js +70 -0
  534. package/ui/js/MdContainer.js +137 -0
  535. package/ui/js/MdDocument.js +337 -0
  536. package/ui/js/MdEmph.js +97 -0
  537. package/ui/js/MdEntity.js +108 -0
  538. package/ui/js/MdEntityTable.js +223 -0
  539. package/ui/js/MdEscape.js +59 -0
  540. package/ui/js/MdFront.js +37 -0
  541. package/ui/js/MdHold.js +32 -0
  542. package/ui/js/MdHtml.js +307 -0
  543. package/ui/js/MdHtmlBlock.js +290 -0
  544. package/ui/js/MdHtmlHeading.js +53 -0
  545. package/ui/js/MdHtmlImage.js +179 -0
  546. package/ui/js/MdInline.js +154 -0
  547. package/ui/js/MdItems.js +212 -0
  548. package/ui/js/MdLeaf.js +309 -0
  549. package/ui/js/MdLink.js +196 -0
  550. package/ui/js/MdMath.js +67 -0
  551. package/ui/js/MdParagraphs.js +138 -0
  552. package/ui/js/MdRefs.js +232 -0
  553. package/ui/js/MdResolve.js +226 -0
  554. package/ui/js/MdRun.js +300 -0
  555. package/ui/js/MdUrl.js +226 -0
  556. package/ui/js/Menu.js +514 -0
  557. package/ui/js/MenuContext.js +85 -0
  558. package/ui/js/MenuFit.js +13 -0
  559. package/ui/js/MenuRefresh.js +74 -0
  560. package/ui/js/MenuWheel.js +35 -0
  561. package/ui/js/Messages.js +186 -0
  562. package/ui/js/Motion.js +16 -0
  563. package/ui/js/Mounts.js +320 -0
  564. package/ui/js/MouseNav.js +13 -0
  565. package/ui/js/Nav.js +329 -0
  566. package/ui/js/NetFs.js +26 -0
  567. package/ui/js/OpenWith.js +83 -0
  568. package/ui/js/Ops.js +585 -0
  569. package/ui/js/Palette.js +33 -0
  570. package/ui/js/PathBar.js +260 -0
  571. package/ui/js/Permissions.js +179 -0
  572. package/ui/js/Phones.js +112 -0
  573. package/ui/js/Picker.js +353 -0
  574. package/ui/js/PlaceMenu.js +96 -0
  575. package/ui/js/Places.js +265 -0
  576. package/ui/js/PreviewAsk.js +21 -0
  577. package/ui/js/PreviewKeys.js +155 -0
  578. package/ui/js/PreviewSettle.js +29 -0
  579. package/ui/js/PreviewSwap.js +101 -0
  580. package/ui/js/PropertyFacts.js +144 -0
  581. package/ui/js/Protocols.js +296 -0
  582. package/ui/js/QuickLookKinds.js +27 -0
  583. package/ui/js/QuickLookRect.js +24 -0
  584. package/ui/js/RailDrop.js +51 -0
  585. package/ui/js/RailKeys.js +87 -0
  586. package/ui/js/RailMenu.js +133 -0
  587. package/ui/js/Recent.js +135 -0
  588. package/ui/js/RecentMode.js +156 -0
  589. package/ui/js/Reload.js +60 -0
  590. package/ui/js/Renderer.js +9 -0
  591. package/ui/js/RunFile.js +143 -0
  592. package/ui/js/Scripts.js +28 -0
  593. package/ui/js/Scroll.js +304 -0
  594. package/ui/js/ScrollOff.js +69 -0
  595. package/ui/js/Search.js +478 -0
  596. package/ui/js/Selection.js +97 -0
  597. package/ui/js/Settings.js +476 -0
  598. package/ui/js/SettingsAbout.js +97 -0
  599. package/ui/js/SettingsShelf.js +52 -0
  600. package/ui/js/SheetKeys.js +42 -0
  601. package/ui/js/SheetQuery.js +281 -0
  602. package/ui/js/ShelfPile.js +27 -0
  603. package/ui/js/SlowClick.js +53 -0
  604. package/ui/js/SlowOp.js +6 -0
  605. package/ui/js/Sort.js +134 -0
  606. package/ui/js/Startup.js +63 -0
  607. package/ui/js/StateWords.js +17 -0
  608. package/ui/js/Status.js +238 -0
  609. package/ui/js/Swap.js +166 -0
  610. package/ui/js/TabMove.js +39 -0
  611. package/ui/js/Tabs.js +736 -0
  612. package/ui/js/Tags.js +134 -0
  613. package/ui/js/Taildrop.js +128 -0
  614. package/ui/js/Tap.js +174 -0
  615. package/ui/js/TextSize.js +107 -0
  616. package/ui/js/Thumbs.js +158 -0
  617. package/ui/js/Transfer.js +172 -0
  618. package/ui/js/Trash.js +81 -0
  619. package/ui/js/TrashDates.js +47 -0
  620. package/ui/js/TrashDrop.js +64 -0
  621. package/ui/js/UiState.js +438 -0
  622. package/ui/js/Unlock.js +152 -0
  623. package/ui/js/Update.js +130 -0
  624. package/ui/js/UserDirs.js +56 -0
  625. package/ui/qmldir +228 -0
@@ -0,0 +1,256 @@
1
+ import QtQuick
2
+ import qs.Commons
3
+ import "js/CodeRuns.js" as CodeRuns
4
+
5
+ // The lines of one file or text, coloured by the backend's code engine, asked a screen-and-margin at a time; a network file's `text` is the caller's.
6
+ Item {
7
+ id: root
8
+
9
+ property var backend: null
10
+ // The backend's name for this view's job; a newer ask on it ends the older one.
11
+ property string slot: "column"
12
+ property string path: ""
13
+ // true sends the bytes in `text` (null until the caller has read them) instead of the path.
14
+ property bool fromText: false
15
+ property var text: null
16
+ property bool active: false
17
+ property bool numbered: false
18
+ property bool wrap: false
19
+ // Enables wheel and drag scrolling in the line viewport.
20
+ property bool scrolls: false
21
+ // Grow from measured delegates only; never scan the entire file to size a lane.
22
+ property real widestLine: 0
23
+ function measureLine(width) {
24
+ if (!root.wrap && isFinite(width) && width > root.widestLine) root.widestLine = width
25
+ }
26
+ readonly property alias viewport: view
27
+ // A Component the list draws above its first line and scrolls with the rows; null for none.
28
+ property Component header: null
29
+ property real pixelSize: Theme.font.caption
30
+ // The most lines drawn, 0 for every line of the file.
31
+ property int limit: 0
32
+ // Screens asked past the view on each side.
33
+ property int margin: 1
34
+ readonly property int lineCap: 400 // The most lines one ask names (docs/protocol.md "code"); a longer window is asked in parts.
35
+
36
+ // A backend that cannot ask (a bare stub) leaves the caller's own text to be drawn plain.
37
+ readonly property bool engine: root.backend !== null && typeof root.backend.askCode === "function"
38
+ // "" until the lines in view are answered, then styled, plain, binary, large or failed.
39
+ property string answer: ""
40
+ property int total: 0
41
+ // The lines held, by 1-based number, read through rowAt; stamp counts changes to it.
42
+ property var held: ({})
43
+ property int stamp: 0
44
+ // The token of the ask in flight, 0 when none: an answer for any other token is dropped.
45
+ property int token: 0
46
+ property bool retiring: false
47
+ // The window of that ask, so the same window is not asked for twice while it is in flight.
48
+ property var asking: null
49
+ readonly property bool settled: root.answer === "styled" || root.answer === "plain"
50
+ readonly property int shown: root.limit > 0 ? Math.min(root.total, root.limit) : root.total
51
+ // True when the lines in view are all held.
52
+ readonly property bool firstScreen: root.settled && root.covered(root.needed().from, root.needed().to)
53
+ // The plain text of the lines drawn, for the readers that check what is on screen.
54
+ readonly property var lines: {
55
+ var out = []
56
+ for (var i = 1; i <= root.shown; i++)
57
+ out.push(root.rowAt(i) ? CodeRuns.plain(root.rowAt(i)) : "")
58
+ return out
59
+ }
60
+ // Indexed by the code reply's role: the foreground, then red, green, yellow, blue, magenta and cyan.
61
+ readonly property var inks: CodeRuns.inks(Theme.palette, Theme.fallbackColor, String(Theme.color.foreground))
62
+ readonly property real rowHeight: metrics.height
63
+ // The gutter is as wide as the widest number it can show, so the text never shifts as it scrolls.
64
+ readonly property real gutterWidth: (Math.max(2, String(root.shown).length) + 1) * metrics.advanceWidth
65
+
66
+ // The runs of line n, undefined until the backend has answered for it; reading it through the stamp makes a binding follow every answer.
67
+ function rowAt(n) {
68
+ return root.stamp >= 0 ? root.held[n] : undefined
69
+ }
70
+
71
+ function reset() {
72
+ root.widestLine = 0
73
+ view.contentX = 0
74
+ view.contentY = 0
75
+ root.held = {}
76
+ root.stamp += 1
77
+ root.total = 0
78
+ root.answer = ""
79
+ root.token = 0
80
+ root.asking = null
81
+ }
82
+
83
+ // Starts a view of a new file or text; the first ask waits for the end of the turn so one change of several properties asks once.
84
+ function fresh() {
85
+ root.reset()
86
+ if (!root.active) {
87
+ askTimer.stop()
88
+ return
89
+ }
90
+ if (!root.engine && root.fromText && root.text !== null)
91
+ root.answerPlain()
92
+ else
93
+ root.schedule()
94
+ }
95
+
96
+ // The owned timer coalesces asks and is destroyed with the reader, including a pending ask during a preview handoff.
97
+ function schedule() {
98
+ if (root.active)
99
+ askTimer.restart()
100
+ }
101
+
102
+ // Sample input: "a\nb\n" holds only lines 1 and 2, as [0, "a"] and [0, "b"], matching the engine's terminal-newline rule.
103
+ function answerPlain() {
104
+ var rows = root.text.length > 0 ? root.text.split("\n") : []
105
+ if (rows.length > 0 && root.text.endsWith("\n"))
106
+ rows.pop()
107
+ var held = {}
108
+ for (var i = 0; i < rows.length && (root.limit <= 0 || i < root.limit); i++)
109
+ held[i + 1] = [0, rows[i].endsWith("\r") ? rows[i].slice(0, -1) : rows[i]]
110
+ root.held = held
111
+ root.stamp += 1
112
+ root.total = rows.length
113
+ root.answer = "plain"
114
+ }
115
+
116
+ // The lines the view needs held: those in it plus the margin, never past the file or the limit.
117
+ function needed() {
118
+ var rows = Math.max(1, Math.ceil(view.height / Math.max(1, root.rowHeight)))
119
+ var top = view.contentHeight > 0 ? Math.max(0, view.indexAt(0, view.contentY + 1)) + 1 : 1
120
+ var to = top + rows * (1 + root.margin) - 1
121
+ if (root.limit > 0)
122
+ to = Math.min(to, root.limit)
123
+ if (root.settled)
124
+ to = Math.min(to, root.total)
125
+ return { from: Math.max(1, top - rows * root.margin), to: to }
126
+ }
127
+
128
+ function covered(from, to) {
129
+ for (var i = from; i <= to; i++)
130
+ if (!root.rowAt(i))
131
+ return false
132
+ return true
133
+ }
134
+
135
+ function ask() {
136
+ if (root.retiring || !root.active || !root.engine || view.height <= 0)
137
+ return
138
+ if (root.answer === "binary" || root.answer === "large" || root.answer === "failed")
139
+ return
140
+ if (root.fromText && root.text === null)
141
+ return
142
+ if (root.fromText && root.text.length === 0) {
143
+ root.answerPlain()
144
+ return
145
+ }
146
+ if (!root.fromText && root.path.length === 0)
147
+ return
148
+ var want = root.needed()
149
+ if (want.to < want.from || (root.settled && root.covered(want.from, want.to)))
150
+ return
151
+ if (root.token !== 0 && root.asking.from === want.from && root.asking.to === want.to)
152
+ return
153
+ root.asking = want
154
+ var from = want.from
155
+ while (from < want.to && root.rowAt(from)) from++
156
+ var source = root.fromText ? { text: root.text, name: root.path.split("/").pop(), lang: "" } : { path: root.path }
157
+ root.token = root.backend.askCode(root.slot, source, from, Math.min(root.lineCap, want.to - from + 1))
158
+ }
159
+
160
+ function answered(message) {
161
+ if (root.token === 0 || message.token !== root.token)
162
+ return
163
+ root.token = 0
164
+ root.answer = message.state
165
+ root.total = message.total || 0
166
+ var rows = message.lines || []
167
+ for (var i = 0; i < rows.length; i++)
168
+ root.held[message.first + i] = rows[i]
169
+ root.stamp += 1
170
+ // Binary, large and failed are the file's whole answer: nothing more is asked of it until the view starts a new one.
171
+ if (root.settled)
172
+ root.schedule()
173
+ }
174
+
175
+ // A pane handoff keeps the engine capability, but disconnects the old backend's request.
176
+ function rebind() {
177
+ root.fresh()
178
+ }
179
+
180
+ onBackendChanged: root.rebind()
181
+ onPathChanged: root.fresh()
182
+ onTextChanged: root.fresh()
183
+ onFromTextChanged: root.fresh()
184
+ onActiveChanged: root.fresh()
185
+ Component.onDestruction: root.retiring = true
186
+ onEngineChanged: root.fresh()
187
+ onLimitChanged: root.schedule()
188
+ onWrapChanged: { view.contentX = 0; root.schedule() }
189
+
190
+ Timer { id: askTimer; interval: 0; onTriggered: root.ask() }
191
+
192
+ Connections {
193
+ target: root.engine ? root.backend : null
194
+ function onCodeResult(message) { root.answered(message) }
195
+ }
196
+
197
+ TextMetrics {
198
+ id: metrics
199
+ font.family: Theme.font.family
200
+ font.pixelSize: root.pixelSize
201
+ text: "0"
202
+ }
203
+
204
+ ListView {
205
+ id: view
206
+ anchors.fill: parent
207
+ clip: true
208
+ interactive: root.scrolls
209
+ flickableDirection: root.wrap ? Flickable.VerticalFlick : Flickable.HorizontalAndVerticalFlick
210
+ contentWidth: root.wrap ? width : Math.max(width, root.widestLine + (root.numbered ? root.gutterWidth : 0))
211
+ cacheBuffer: 0
212
+ boundsBehavior: Flickable.StopAtBounds
213
+ model: root.shown
214
+ header: root.header
215
+ onContentYChanged: root.schedule()
216
+ onHeightChanged: root.schedule()
217
+
218
+ delegate: Item {
219
+ id: line
220
+ required property int index
221
+ readonly property var runs: root.rowAt(line.index + 1)
222
+ width: view.contentWidth
223
+ height: Math.max(body.implicitHeight, root.rowHeight)
224
+
225
+ Text {
226
+ visible: root.numbered
227
+ width: root.gutterWidth
228
+ text: String(line.index + 1)
229
+ horizontalAlignment: Text.AlignRight
230
+ color: Theme.color.muted
231
+ opacity: 0.6
232
+ font.family: Theme.font.family
233
+ font.pixelSize: Theme.font.caption
234
+ textFormat: Text.PlainText
235
+ }
236
+
237
+ // corner: file contents are arbitrary text, so every run is escaped and the string holds only the font tags written here.
238
+ Text {
239
+ id: body
240
+ x: root.numbered ? root.gutterWidth : 0
241
+ width: line.width - x
242
+ leftPadding: 2 * metrics.advanceWidth
243
+ text: line.runs ? CodeRuns.styled(line.runs, root.inks) : ""
244
+ color: Theme.color.foreground
245
+ font.family: Theme.font.family
246
+ font.pixelSize: root.pixelSize
247
+ textFormat: Text.StyledText
248
+ wrapMode: root.wrap ? Text.WrapAtWordBoundaryOrAnywhere : Text.NoWrap
249
+ // Keep the complete line; the viewport clips and pans it instead of eliding.
250
+ elide: Text.ElideNone
251
+ onImplicitWidthChanged: root.measureLine(implicitWidth)
252
+ Component.onCompleted: root.measureLine(implicitWidth)
253
+ }
254
+ }
255
+ }
256
+ }
@@ -0,0 +1,52 @@
1
+ import QtQuick
2
+ import "." as Flea
3
+
4
+ // The code preview's refusal frame, shared by Quick Look's text pane and Markdown Source.
5
+ Item {
6
+ id: root
7
+
8
+ property bool binary: false
9
+ property bool tooLarge: false
10
+ property bool failed: false
11
+ property string markName: "file"
12
+ // Quick Look places the frame below its bar; Source's host has already set that inset.
13
+ property int topInset: 0
14
+ readonly property string status: root.tooLarge ? "This file is too large to preview." : root.failed ? "This file could not be read." : "ready"
15
+
16
+ Column {
17
+ anchors.horizontalCenter: parent.horizontalCenter
18
+ y: root.topInset + Math.round((parent.height - root.topInset - height) / 2)
19
+ spacing: Theme.spacing.gap
20
+ visible: root.binary || (root.tooLarge && !root.failed)
21
+
22
+ Flea.Glyph {
23
+ anchors.horizontalCenter: parent.horizontalCenter
24
+ maxSize: Theme.stateMarkSize
25
+ width: Theme.stateMarkSize
26
+ height: Theme.stateMarkSize
27
+ name: root.markName
28
+ color: Theme.color.muted
29
+ opacity: 0.7
30
+ }
31
+
32
+ Text {
33
+ anchors.horizontalCenter: parent.horizontalCenter
34
+ text: root.binary ? "binary file" : "too large to preview"
35
+ color: Theme.color.muted
36
+ font.family: Theme.font.family
37
+ font.pixelSize: Theme.font.caption
38
+ textFormat: Text.PlainText
39
+ }
40
+ }
41
+
42
+ Text {
43
+ anchors.horizontalCenter: parent.horizontalCenter
44
+ y: root.topInset + Math.round((parent.height - root.topInset - height) / 2)
45
+ visible: false // A failed preview remains blank.
46
+ text: root.status
47
+ color: Theme.color.muted
48
+ font.family: Theme.font.family
49
+ font.pixelSize: Theme.font.body
50
+ textFormat: Text.PlainText
51
+ }
52
+ }
@@ -0,0 +1,147 @@
1
+ import QtQuick
2
+ import qs.Commons
3
+ import "." as Flea
4
+ import "js/Collide.js" as Collide
5
+ import "js/Icons.js" as Icons
6
+
7
+ // One choice for every name a paste or a drop would land on, on ui/TrashConfirm.qml's card, keys and look.
8
+ FocusScope {
9
+ id: root
10
+ anchors.fill: parent
11
+ visible: opened || opacity > 0
12
+ // Closed means no input, even while the fade-out is still drawn.
13
+ enabled: opened
14
+ opacity: 0
15
+ property bool opened: false
16
+ property string titleText: ""
17
+ property var names: []
18
+ property string moreText: ""
19
+ property string focusName: Collide.START
20
+ // Merge is present only when a folder lands on a folder; the second card never offers it.
21
+ property bool showMerge: false
22
+ readonly property string explainText: Collide.EXPLAIN
23
+ readonly property real referenceScale: Collide.cardReferenceScale(Theme.font.bodySmall)
24
+ readonly property real cardPadding: Collide.cardPadding(referenceScale)
25
+ readonly property real cardBottomPadding: Math.round(12 * referenceScale)
26
+ // MergeFolders: the buttons keep 6 px of air over the gap.
27
+ readonly property real buttonsAir: Math.round(6 * referenceScale)
28
+ // The card grows with the labels rather than wrapping one, and Keep both stays the default with the ring.
29
+ readonly property real contentWidth: Collide.cardContentWidth(referenceScale, Theme.dialogWidthRatio, buttons.implicitWidth)
30
+ signal chosen(string choice)
31
+ readonly property var cardItem: card
32
+ readonly property bool titleTruncated: title.truncated
33
+ readonly property bool buttonsFit: buttons.width <= body.holderWidth
34
+ readonly property int explainLines: explain.lineCount
35
+ function buttonItem(name) { return ({cancel: cancelButton, skip: skipButton, keep: keepButton, merge: mergeButton, replace: replaceButton})[name] || null }
36
+ function open(heading, list, more, merge) {
37
+ titleText = heading
38
+ names = list
39
+ moreText = more
40
+ showMerge = merge === true
41
+ // A hidden Merge never holds the ring: the card opens on Keep both either way.
42
+ focusName = Collide.START
43
+ body.contentY = 0
44
+ opened = true
45
+ forceActiveFocus()
46
+ }
47
+ function choose(choice) {
48
+ opened = false
49
+ chosen(choice)
50
+ }
51
+ Flea.Reveal { target: root; shown: root.opened; lift: card }
52
+ // A press lands on its own button first, so the accent never shows one choice while another is taken.
53
+ function press(choice) {
54
+ focusName = choice
55
+ choose(choice)
56
+ }
57
+ Keys.onPressed: function(event) {
58
+ if (event.key === Qt.Key_Escape) root.choose("cancel")
59
+ else if (event.modifiers & (Qt.ControlModifier | Qt.AltModifier | Qt.MetaModifier)) { event.accepted = true; return }
60
+ else if (Collide.activates(event.key)) root.choose(root.focusName)
61
+ else root.focusName = Collide.moved(root.focusName, event.key, root.showMerge, event.modifiers)
62
+ if (root.opened) body.reveal(root.buttonItem(root.focusName))
63
+ event.accepted = true
64
+ }
65
+ Flea.DialogScrim {
66
+ onDismissed: root.choose("cancel")
67
+ }
68
+ Rectangle {
69
+ id: card
70
+ x: Theme.cardOrigin(root.width, width)
71
+ y: Theme.cardOrigin(root.height, height)
72
+ width: Theme.cardSpan(root.contentWidth + 2 * root.cardPadding + 2 * Theme.spacing.hairline, root.width - 2 * Theme.spacing.gap)
73
+ height: Theme.cardSpan(body.wanted + root.cardPadding + root.cardBottomPadding + 2 * Theme.spacing.hairline, root.height - 2 * Theme.spacing.gap)
74
+ color: Theme.color.surface
75
+ border.color: Theme.color.mutedFrame
76
+ border.width: Theme.spacing.hairline
77
+ radius: Style.cornerRadius
78
+ MouseArea {
79
+ anchors.fill: parent
80
+ hoverEnabled: true
81
+ acceptedButtons: Qt.LeftButton | Qt.RightButton
82
+ onWheel: function(wheel) { wheel.accepted = true }
83
+ }
84
+ Flea.CardFrame {
85
+ id: body
86
+ bleed: Theme.focusClearance
87
+ anchors.fill: parent
88
+ anchors.leftMargin: root.cardPadding + Theme.spacing.hairline - Theme.focusClearance
89
+ anchors.rightMargin: root.cardPadding + Theme.spacing.hairline - Theme.focusClearance
90
+ anchors.topMargin: root.cardPadding + Theme.spacing.hairline - Theme.focusClearance
91
+ anchors.bottomMargin: root.cardBottomPadding + Theme.spacing.hairline - Theme.focusClearance
92
+ title: Flea.DialogHeader {
93
+ id: title
94
+ width: parent.width
95
+ text: root.titleText
96
+ }
97
+ buttons: Row {
98
+ id: buttons
99
+ anchors.right: parent.right
100
+ topPadding: root.buttonsAir
101
+ spacing: Theme.spacing.gap
102
+ Flea.DialogButton { id: cancelButton; label: Collide.LABELS.cancel; focused: root.focusName === "cancel"; onActivated: root.press("cancel") }
103
+ Flea.DialogButton { id: skipButton; label: Collide.LABELS.skip; focused: root.focusName === "skip"; onActivated: root.press("skip") }
104
+ Flea.DialogButton { id: keepButton; label: Collide.LABELS.keep; primary: true; focused: root.focusName === "keep"; onActivated: root.press("keep") }
105
+ Flea.DialogButton { id: mergeButton; visible: root.showMerge; label: Collide.LABELS.merge; focused: root.focusName === "merge"; onActivated: root.press("merge") }
106
+ Flea.DialogButton { id: replaceButton; label: Collide.LABELS.replace; destructive: true; focused: root.focusName === "replace"; onActivated: root.press("replace") }
107
+ }
108
+ Column {
109
+ width: parent.width
110
+ spacing: Theme.spacing.gap
111
+ Column {
112
+ width: parent.width
113
+ Repeater {
114
+ model: root.names
115
+ delegate: Row {
116
+ id: nameRow
117
+ required property var modelData
118
+ width: parent.width
119
+ height: Theme.fileRowHeight
120
+ spacing: Theme.spacing.gap
121
+ Flea.Glyph { width: Theme.markSize; height: parent.height; name: nameRow.modelData.d ? "folder" : Icons.glyphFor(nameRow.modelData.i); color: Theme.color.foreground }
122
+ Text { width: Math.max(0, parent.width - Theme.markSize - parent.spacing); anchors.verticalCenter: parent.verticalCenter; text: nameRow.modelData.n; textFormat: Text.PlainText; elide: Text.ElideRight; color: Theme.color.foreground; font { family: Theme.font.family; pixelSize: Theme.font.body } }
123
+ }
124
+ }
125
+ Text {
126
+ width: parent.width
127
+ visible: root.moreText.length > 0
128
+ text: root.moreText
129
+ textFormat: Text.PlainText
130
+ elide: Text.ElideRight
131
+ color: Theme.color.foreground
132
+ font { family: Theme.font.family; pixelSize: Theme.font.caption }
133
+ }
134
+ }
135
+ Text {
136
+ id: explain
137
+ width: parent.width
138
+ text: root.explainText
139
+ textFormat: Text.PlainText
140
+ wrapMode: Text.Wrap
141
+ color: Theme.color.foreground
142
+ font { family: Theme.font.family; pixelSize: Theme.font.caption }
143
+ }
144
+ }
145
+ }
146
+ }
147
+ }
@@ -0,0 +1,167 @@
1
+ import QtQuick
2
+ import "js/Clipboard.js" as Clipboard
3
+ import "js/Collide.js" as Collide
4
+
5
+ // A pane's question before a transfer lands on names that exist: the transfer waits here, so Cancel sends nothing.
6
+ Loader {
7
+ id: root
8
+ required property var pane
9
+ anchors.fill: parent
10
+ z: 2
11
+ // Built by the first question that collides, see AGENTS.md rule 6: a hidden card is not a free one.
12
+ active: false
13
+ source: "CollideConfirm.qml"
14
+ readonly property bool opened: item !== null && item.opened
15
+ // The transfer waiting on the answer, or null, and whether sending it spends a cut clipboard.
16
+ property var pending: null
17
+ property bool spendsCut: false
18
+ property var cutClipboard: null
19
+ property int askId: 0
20
+ // A merge holds its transfer across two cards: the walk's answer lands on the second.
21
+ property bool merging: false
22
+ property var outerNames: []
23
+ // How many names the first card counted, of which outerNames shows at most three.
24
+ property int outerTotal: 0
25
+ property var probe: null
26
+ // Built by the first FAT answer, with no placeholder: a Loader here would stand at startup for a card most windows never open.
27
+ property var fatCard: null
28
+
29
+ // A cut is spent when its transfer goes out, so a Cancel leaves it on the clipboard to paste elsewhere.
30
+ function ask(request, probe, cut) {
31
+ var refused = Collide.refusal(root.opened, root.pending)
32
+ if (refused.length > 0) {
33
+ root.pane.message(refused, false)
34
+ return false
35
+ }
36
+ root.askId += 1
37
+ // Its rows keep the numbering they were read in, so a listing landing before the answer gets the transfer refused, not resolved anew.
38
+ root.pending = Collide.waiting(request, root.pane.backend.heldListing)
39
+ root.spendsCut = cut === true
40
+ root.cutClipboard = cut === true ? root.pane.clipboard : null
41
+ root.merging = false
42
+ root.outerNames = []
43
+ root.probe = probe || null
44
+ root.pane.backend.send(Collide.question(root.pending, probe, root.askId))
45
+ return true
46
+ }
47
+
48
+ // A merge's terminal line; only a merge this card asked carries into, so every other line is the pane's own.
49
+ function doneLine(transfer, result) {
50
+ return Collide.doneLine(transfer, result)
51
+ }
52
+
53
+ // Nothing collided: the transfer goes out as it would have, carrying the refusal for any late name.
54
+ function answered(id, total, names, mergeable) {
55
+ if (id !== root.askId || root.pending === null)
56
+ return
57
+ if (total === 0) {
58
+ root.decide(Collide.NONE)
59
+ return
60
+ }
61
+ root.outerNames = names
62
+ root.outerTotal = total
63
+ root.active = true
64
+ // Paste as links never merges: the Merge card is the transfer's own second card.
65
+ root.item.open(Collide.title(names, total, root.pending.dest), names, Collide.more(total, names.length),
66
+ mergeable === true && root.pending.c !== "link")
67
+ }
68
+
69
+ // The destination cannot hold some names: Rename and copy or Skip them rides the question again, before any collision is asked.
70
+ function answeredFat(id, renames, fstype, volume) {
71
+ if (id !== root.askId || root.pending === null)
72
+ return
73
+ if (root.fatCard === null) {
74
+ root.fatCard = Qt.createComponent("FatNamesConfirm.qml").createObject(root.parent, { z: root.z })
75
+ root.fatCard.chosen.connect(root.decideFat)
76
+ }
77
+ root.fatCard.open(Collide.cardTitle(renames.length, volume, fstype), renames, Collide.cardNote(fstype))
78
+ }
79
+
80
+ function decideFat(choice) {
81
+ if (choice === "cancel" || root.pending === null) {
82
+ root.decide("cancel")
83
+ } else {
84
+ root.pending.fat = choice
85
+ root.pane.backend.send(Collide.question(root.pending, root.probe, root.askId))
86
+ }
87
+ root.pane.listArea.forceActiveFocus()
88
+ }
89
+
90
+ // The second card: what files inside the merging folders already exist, asked by one walk before anything is written.
91
+ function answeredMerge(id, total, names) {
92
+ if (id !== root.askId || root.pending === null || !root.merging)
93
+ return
94
+ if (total === 0) {
95
+ root.decideMerge("refuse")
96
+ return
97
+ }
98
+ var into = Collide.mergeDest(root.pending, root.outerNames, root.outerTotal)
99
+ root.item.open(Collide.title(names, total, into), names, Collide.more(total, names.length), false)
100
+ }
101
+
102
+ // Merge leaves the first card for the walk: the transfer waits on the second answer, not this one.
103
+ function decide(choice) {
104
+ if (choice === "merge") {
105
+ root.merging = true
106
+ root.pane.backend.send(Collide.mergeQuestion(root.pending, root.probe, root.askId))
107
+ return
108
+ }
109
+ var request = root.pending
110
+ if (request && choice !== "cancel") {
111
+ // MenuAdditions040: Paste as links asks through this same card.
112
+ root.pane.backend.send(request.c === "link" ? Collide.link(request, choice, root.askId)
113
+ : Collide.transfer(request, choice, root.askId))
114
+ Clipboard.spent(root.pane, root.cutClipboard, root.spendsCut)
115
+ }
116
+ root.pending = null
117
+ root.cutClipboard = null
118
+ root.merging = false
119
+ root.outerNames = []
120
+ root.probe = null
121
+ }
122
+
123
+ // The second card's answer rides the merge transfer; Cancel sends nothing and keeps the cut.
124
+ function decideMerge(choice) {
125
+ var request = root.pending
126
+ if (request && choice !== "cancel") {
127
+ root.pane.backend.send(Collide.mergeTransfer(request, choice, root.askId))
128
+ Clipboard.spent(root.pane, root.cutClipboard, root.spendsCut)
129
+ }
130
+ root.pending = null
131
+ root.cutClipboard = null
132
+ root.merging = false
133
+ root.outerNames = []
134
+ root.probe = null
135
+ }
136
+
137
+ Connections {
138
+ target: root.pane.backend
139
+ function onCollisions(id, total, names, mergeable) { root.answered(id, total, names, mergeable) }
140
+ function onMergeCollisions(id, total, names) { root.answeredMerge(id, total, names) }
141
+ function onFatnames(id, renames, fstype, volume) { root.answeredFat(id, renames, fstype, volume) }
142
+ // A dead backend or a refused question ends the wait here and closes the card.
143
+ function onFailed(where, input) {
144
+ if (where === "backend" || Collide.droppedPending(where, input)) {
145
+ root.pending = null
146
+ root.cutClipboard = null
147
+ root.merging = false
148
+ root.outerNames = []
149
+ root.probe = null
150
+ if (root.item)
151
+ root.item.opened = false
152
+ if (root.fatCard !== null)
153
+ root.fatCard.opened = false
154
+ }
155
+ }
156
+ }
157
+ Connections {
158
+ target: root.item
159
+ function onChosen(choice) {
160
+ if (root.merging)
161
+ root.decideMerge(choice)
162
+ else
163
+ root.decide(choice)
164
+ root.pane.listArea.forceActiveFocus()
165
+ }
166
+ }
167
+ }