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,133 @@
1
+ import QtQuick
2
+ import "js/Filter.js" as Filter
3
+ import "js/Focus.js" as Focus
4
+
5
+ // The filter's query line: the funnel mark, the query with its caret, and the caveat when the pane
6
+ // is not holding the whole listing. Presentation only, the way ui/SearchStrip.qml is; ui/Pane.qml
7
+ // owns every value it draws and ui/js/Filter.js owns every transition.
8
+ //
9
+ // It sits below the column header rather than covering it, which is what the search's own strip
10
+ // does: the sort mark has to stay readable, because filtering a sorted view keeps that order.
11
+ Item {
12
+ id: root
13
+
14
+ property var pane: null
15
+
16
+ readonly property bool up: !root.pane.trash.opened && (root.pane.filterTyping || root.pane.filterQuery.length > 0)
17
+ readonly property real ruleOpacity: 0.12
18
+ // Twice the hairline, the same weight the cursor row's mark uses, so one caret rule serves both.
19
+ readonly property int caretWidth: Theme.spacing.hairline * 2
20
+
21
+ // A chrome strip is not a data row; see Theme.qml's chromeHeight comment. Collapsing rather than
22
+ // only hiding is what keeps the rows starting at the top of the pane when no filter is up.
23
+ implicitHeight: Theme.chromeHeight
24
+ visible: root.up
25
+ height: root.up ? implicitHeight : 0
26
+
27
+ // SearchFilter rule 4: the funnel sits on the pane's own ground, where the magnifier sits on the
28
+ // raised chrome, because a filter is about the listing under it and a search is not about here.
29
+ Rectangle {
30
+ anchors.fill: parent
31
+ color: Glass.on ? "transparent" : Theme.color.background
32
+ }
33
+
34
+ Rectangle {
35
+ anchors.bottom: parent.bottom
36
+ anchors.left: parent.left
37
+ anchors.right: parent.right
38
+ height: Theme.spacing.hairline
39
+ color: Theme.color.foreground
40
+ opacity: root.ruleOpacity
41
+ }
42
+
43
+ Glyph {
44
+ id: mark
45
+ anchors.left: parent.left
46
+ anchors.leftMargin: Theme.spacing.rowPaddingX
47
+ anchors.verticalCenter: parent.verticalCenter
48
+ // The chrome mark token, the size the search strip's own lens is drawn at.
49
+ width: Theme.chromeMarkSize
50
+ height: Theme.chromeMarkSize
51
+ name: "filter"
52
+ color: Theme.color.accent
53
+ }
54
+
55
+ // flea-qml: a real text field, as Find's is: the caret moves, blinks and selects, and copy and paste
56
+ // work as in any input. Every edit narrows through Filter.apply, the one writer of the query; the
57
+ // keys that are not editing go to the pane's own route, so Enter still hands the keyboard to the
58
+ // list with the filter standing, and Esc and the arrows behave as before.
59
+ TextInput {
60
+ id: field
61
+ objectName: "filterInput"
62
+ anchors.left: mark.right
63
+ anchors.leftMargin: Theme.spacing.gap
64
+ anchors.verticalCenter: parent.verticalCenter
65
+ width: Math.min(Math.max(contentWidth, Theme.chromeMarkSize) + root.caretWidth * 2, Math.max(0, root.width / 2))
66
+ clip: true
67
+ text: root.pane.filterQuery
68
+ color: Theme.color.foreground
69
+ selectionColor: Theme.color.accent
70
+ selectedTextColor: Theme.color.background
71
+ font.family: Theme.font.family
72
+ font.pixelSize: Theme.font.body
73
+ selectByMouse: true
74
+ onTextEdited: Filter.apply(root.pane, text)
75
+ // A click into the field takes the filter back to typing.
76
+ onActiveFocusChanged: if (activeFocus && !root.pane.filterTyping) root.pane.filterTyping = true
77
+ Keys.onPressed: function (event) {
78
+ switch (event.key) {
79
+ case Qt.Key_Return: case Qt.Key_Enter: case Qt.Key_Escape:
80
+ case Qt.Key_Up: case Qt.Key_Down: case Qt.Key_PageUp: case Qt.Key_PageDown:
81
+ event.accepted = Focus.handleKey(event, root.pane, root.pane.sidebar, "filter")
82
+ }
83
+ }
84
+ }
85
+ // Typing gives the field the keyboard; standing or closing hands it back to the list.
86
+ Connections {
87
+ target: root.pane
88
+ function onFilterTypingChanged() {
89
+ if (root.pane.filterTyping) Qt.callLater(field.forceActiveFocus)
90
+ else if (field.activeFocus && root.pane.listArea) root.pane.listArea.forceActiveFocus()
91
+ }
92
+ }
93
+
94
+ // SearchFilter rule 1: the strip owns what it created, so the count and its scope read here and
95
+ // no sentence is left standing in the listing, where it would be a row that is not a file.
96
+ Text {
97
+ id: summaryText
98
+ anchors.left: field.right
99
+ anchors.leftMargin: Theme.spacing.gap
100
+ anchors.right: wayOut.left
101
+ anchors.rightMargin: Theme.spacing.gap
102
+ anchors.verticalCenter: parent.verticalCenter
103
+ elide: Text.ElideRight
104
+ text: Filter.summary(root.pane.shown, root.pane.rows.length, root.pane.total)
105
+ color: Theme.color.muted
106
+ font.family: Theme.font.family
107
+ font.pixelSize: Theme.font.caption
108
+ textFormat: Text.PlainText
109
+ }
110
+
111
+ Text {
112
+ id: wayOut
113
+ anchors.right: closeButton.left
114
+ anchors.rightMargin: Theme.spacing.gap
115
+ anchors.verticalCenter: parent.verticalCenter
116
+ text: "esc clears"
117
+ color: Theme.color.muted
118
+ font.family: Theme.font.family
119
+ font.pixelSize: Theme.font.caption
120
+ textFormat: Text.PlainText
121
+ }
122
+
123
+ // flea-qml: ✕ clears and closes the filter, what Esc does from the list.
124
+ ChromeButton {
125
+ id: closeButton
126
+ anchors.right: parent.right
127
+ anchors.rightMargin: Theme.spacing.rowPaddingX
128
+ anchors.verticalCenter: parent.verticalCenter
129
+ glyph: "x"
130
+ accessName: "Close filter"
131
+ onActivated: Filter.close(root.pane)
132
+ }
133
+ }
@@ -0,0 +1,22 @@
1
+ import QtQuick
2
+ import "js/ColumnFit.js" as ColumnFit
3
+
4
+ // Fit-only metrics, so Header carries no fit helper until a fit runs.
5
+ Item {
6
+ TextMetrics {
7
+ id: fitText
8
+ font.family: Theme.font.family
9
+ font.pixelSize: Theme.font.caption
10
+ }
11
+
12
+ // One held row's measured width, in the cells' own caption face.
13
+ function cellWidth(key, row, kindNames, dirSize) {
14
+ fitText.text = ColumnFit.cellText(key, row, kindNames, dirSize)
15
+ return Math.ceil(fitText.advanceWidth)
16
+ }
17
+
18
+ // The held index behind one held row, for the dirsize the row would draw.
19
+ function dirSizeFor(state, held, at) {
20
+ return ColumnFit.dirSizeFor(state, held, at)
21
+ }
22
+ }
@@ -0,0 +1,137 @@
1
+ import QtQuick
2
+ import qs.Commons
3
+ import "." as Flea
4
+ import "js/Flash.js" as Flash
5
+ import "js/Format.js" as Format
6
+
7
+ // The DRIVES step: one file row per drive with its refusal hint, or the empty row while no drive is plugged in.
8
+ Column {
9
+ id: root
10
+ property var drives: []
11
+ property bool drivesReady: false
12
+ property int selected: -1
13
+ property int cursor: 0
14
+ property bool focused: true
15
+ property bool running: false
16
+ signal chooseDrive(int index)
17
+ width: 0
18
+ // The board's detail column, 190 px at bodySmall 13, scaled with the text.
19
+ readonly property int detailBoard: 190
20
+ readonly property int bodySmallBoard: 13
21
+ Text {
22
+ x: Theme.spacing.rowPaddingX
23
+ // A later section opens a panel gap under the one above, as the rail's FAVORITES does.
24
+ topPadding: Math.round(Style.spacing.panelGap * Theme.sizeRatio) + Math.ceil(font.pixelSize * 0.15)
25
+ bottomPadding: Theme.spacing.gap
26
+ text: "DRIVES"
27
+ color: Theme.color.muted
28
+ font.family: Theme.font.family
29
+ font.pixelSize: Theme.font.caption
30
+ font.letterSpacing: 1
31
+ textFormat: Text.PlainText
32
+ }
33
+ Repeater {
34
+ model: root.drives
35
+ delegate: Column {
36
+ required property var modelData
37
+ required property int index
38
+ // Read once through the delegate: every bare modelData or index below would warn on its own.
39
+ readonly property var row: modelData
40
+ readonly property int idx: index
41
+ // Detail ink lifts to foreground on the cursor or chosen row, muted at rest.
42
+ readonly property color detailInk: (root.cursor === idx + 1 || root.selected === idx) ? Theme.color.foreground : Theme.color.muted
43
+ width: root.width
44
+ Rectangle {
45
+ width: parent.width
46
+ height: Theme.fileRowHeight
47
+ // The cursor uses accent ink; the chosen drive keeps the marked rung, as Row.qml draws both.
48
+ color: root.cursor === idx + 1 ? (root.focused ? Style.selectedAccentFill : "transparent")
49
+ : root.selected === idx ? Style.selectionFill : "transparent"
50
+ opacity: Flash.fits(row) ? 1 : Theme.disabledOpacity
51
+ Rectangle {
52
+ visible: root.cursor === idx + 1
53
+ width: Theme.spacing.hairline * 2
54
+ height: parent.height
55
+ color: root.focused ? Theme.color.accent : Theme.color.mutedFrame
56
+ }
57
+ Row {
58
+ anchors.fill: parent
59
+ anchors.leftMargin: Theme.spacing.rowPaddingX
60
+ anchors.rightMargin: Theme.spacing.rowPaddingX
61
+ spacing: Theme.spacing.gap
62
+ Flea.Glyph { width: Theme.markSize; height: parent.height; name: "drive"; color: Theme.color.foreground }
63
+ Text {
64
+ width: Math.max(0, parent.width - Theme.markSize - driveDetail.width - driveSize.width - 3 * parent.spacing)
65
+ anchors.verticalCenter: parent.verticalCenter
66
+ text: row ? Flash.driveName(row, root.drives) : ""
67
+ textFormat: Text.PlainText
68
+ elide: Text.ElideRight
69
+ color: Theme.color.foreground
70
+ font { family: Theme.font.family; pixelSize: Theme.font.body }
71
+ }
72
+ Text {
73
+ id: driveDetail
74
+ width: Math.round(root.detailBoard * Theme.font.bodySmall / root.bodySmallBoard)
75
+ anchors.verticalCenter: parent.verticalCenter
76
+ text: row ? Flash.driveDetail(row, root.drives) : ""
77
+ textFormat: Text.PlainText
78
+ elide: Text.ElideRight
79
+ color: detailInk
80
+ font { family: Theme.font.family; pixelSize: Theme.font.caption }
81
+ }
82
+ Text {
83
+ id: driveSize
84
+ width: Theme.column.size
85
+ anchors.verticalCenter: parent.verticalCenter
86
+ horizontalAlignment: Text.AlignRight
87
+ text: row ? Format.size(row.bytes) : ""
88
+ textFormat: Text.PlainText
89
+ elide: Text.ElideRight
90
+ color: detailInk
91
+ font { family: Theme.font.family; pixelSize: Theme.font.caption }
92
+ }
93
+ }
94
+ MouseArea {
95
+ anchors.fill: parent
96
+ acceptedButtons: Qt.LeftButton
97
+ onClicked: {
98
+ if (!root.running && Flash.fits(row))
99
+ root.chooseDrive(idx)
100
+ }
101
+ }
102
+ }
103
+ Text {
104
+ visible: !Flash.fits(row)
105
+ x: Theme.spacing.rowPaddingX + Theme.markSize + Theme.spacing.gap
106
+ topPadding: Theme.spacing.rowPaddingY
107
+ bottomPadding: Theme.spacing.rowPaddingY
108
+ width: parent.width - x - Theme.spacing.rowPaddingX
109
+ wrapMode: Text.Wrap
110
+ text: Flash.refusedHint(row)
111
+ color: Theme.color.muted
112
+ font { family: Theme.font.family; pixelSize: Theme.font.caption }
113
+ textFormat: Text.PlainText
114
+ }
115
+ }
116
+ }
117
+ Item {
118
+ visible: root.drivesReady && root.drives.length === 0
119
+ width: root.width
120
+ height: Theme.fileRowHeight
121
+ Row {
122
+ anchors.fill: parent
123
+ anchors.leftMargin: Theme.spacing.rowPaddingX
124
+ anchors.rightMargin: Theme.spacing.rowPaddingX
125
+ spacing: Theme.spacing.gap
126
+ Flea.Glyph { width: Theme.markSize; height: parent.height; name: "drive"; color: Theme.color.mutedFrame }
127
+ Text {
128
+ anchors.verticalCenter: parent.verticalCenter
129
+ text: "Plug in a USB drive or SD card"
130
+ textFormat: Text.PlainText
131
+ elide: Text.ElideRight
132
+ color: Theme.color.muted
133
+ font { family: Theme.font.family; pixelSize: Theme.font.body }
134
+ }
135
+ }
136
+ }
137
+ }
@@ -0,0 +1,72 @@
1
+ import QtQuick
2
+ import "js/Focus.js" as Focus
3
+ import "js/Flash.js" as Flash
4
+ import "js/FlashPane.js" as FlashPane
5
+
6
+ // Built once per window on first use with no placeholder; one host serves every later open and marks its pane active.
7
+ Loader {
8
+ id: root
9
+ property var coverPane: null
10
+ active: false
11
+ visible: opened
12
+ readonly property bool opened: item !== null && item.opened
13
+ readonly property int count: item ? item.driveCount : 0
14
+ // The counts zone's own line while the host owns the pane, read by the window.
15
+ readonly property string countText: Flash.drivesLine(root.count)
16
+
17
+ // Covers the opening pane's slot as Trash does; a second pane cannot take it while a flash runs.
18
+ function openFor(pane, image, device) {
19
+ if (root.item && root.item.pane !== pane && root.item.transfer.running === true) {
20
+ pane.message(Flash.alreadyRunning(), false)
21
+ return
22
+ }
23
+ FlashPane.cover(root, pane)
24
+ root.parent = pane
25
+ root.anchors.fill = pane
26
+ root.anchors.leftMargin = pane.sidebarWidth
27
+ root.active = true
28
+ if (!root.item || root.item.pane !== pane)
29
+ root.setSource("FlashView.qml", { pane: pane, statusBar: pane.statusBar })
30
+ if (image && image.length > 0)
31
+ root.item.openWithImage(image)
32
+ else
33
+ root.item.openWithDrive(device)
34
+ }
35
+ function close() {
36
+ if (root.opened)
37
+ root.item.close()
38
+ FlashPane.uncover(root)
39
+ }
40
+ // The read-only seam's own flash readers, so ui/Ipc.qml stays one call per entry point.
41
+ function describe() {
42
+ var view = root.item
43
+ if (!view)
44
+ return "{\"opened\":false}"
45
+ return JSON.stringify({ opened: view.opened, cursor: view.cursor,
46
+ image: view.image ? view.image.path : "", drives: view.drives.length,
47
+ selected: view.selected, live: view.live, running: view.running,
48
+ phase: view.running ? view.transfer.phase : "",
49
+ ending: view.ending ? view.ending.headline : "" })
50
+ }
51
+ function controlItem(name) {
52
+ var view = root.item
53
+ if (!view)
54
+ return null
55
+ return name === "flash" ? view.flashItem : name === "cancel" ? view.cancelItem
56
+ : name === "end" ? view.endItem : null
57
+ }
58
+ Connections {
59
+ target: root.item
60
+ function onBackRequested() {
61
+ if (!root.coverPane)
62
+ return
63
+ FlashPane.uncover(root)
64
+ root.coverPane.focusView = Focus.LIST
65
+ root.coverPane.listArea.forceActiveFocus()
66
+ }
67
+ function onFocusRailRequested() {
68
+ if (root.coverPane)
69
+ root.coverPane.focusView = Focus.RAIL
70
+ }
71
+ }
72
+ }
@@ -0,0 +1,104 @@
1
+ import QtQuick
2
+ import qs.Commons
3
+ import "." as Flea
4
+ import "js/Flash.js" as Flash
5
+ import "js/Format.js" as Format
6
+
7
+ // The IMAGE step: heading, the chosen image with its sizes or the picker row, and the refusal hint under a refused image.
8
+ Column {
9
+ id: root
10
+ property var image: null
11
+ property bool cursor: false
12
+ property bool focused: true
13
+ property bool running: false
14
+ signal choose()
15
+ width: 0
16
+ // The board's detail column, 190 px at bodySmall 13, scaled with the text.
17
+ readonly property int detailBoard: 190
18
+ readonly property int bodySmallBoard: 13
19
+ // Detail ink lifts to foreground under the cursor, muted at rest, as Row.qml cellInk does.
20
+ readonly property color detailInk: root.cursor ? Theme.color.foreground : Theme.color.muted
21
+ Text {
22
+ x: Theme.spacing.rowPaddingX
23
+ // The first section opens one row padding under the strip, as the rail's PLACES does.
24
+ topPadding: Theme.spacing.rowPaddingX + Math.ceil(font.pixelSize * 0.15)
25
+ bottomPadding: Theme.spacing.gap
26
+ text: "IMAGE"
27
+ color: Theme.color.muted
28
+ font.family: Theme.font.family
29
+ font.pixelSize: Theme.font.caption
30
+ font.letterSpacing: 1
31
+ textFormat: Text.PlainText
32
+ }
33
+ Rectangle {
34
+ width: root.width
35
+ height: Theme.fileRowHeight
36
+ // The cursor uses accent ink, as every listing row does; a refused image only dims.
37
+ color: root.cursor ? (root.focused ? Style.selectedAccentFill : "transparent") : "transparent"
38
+ opacity: root.image && root.image.refused ? Theme.disabledOpacity : 1
39
+ // Twice the hairline, the cursor mark against the row edge, as Row.qml draws it.
40
+ Rectangle {
41
+ visible: root.cursor
42
+ width: Theme.spacing.hairline * 2
43
+ height: parent.height
44
+ color: root.focused ? Theme.color.accent : Theme.color.mutedFrame
45
+ }
46
+ Row {
47
+ anchors.fill: parent
48
+ anchors.leftMargin: Theme.spacing.rowPaddingX
49
+ anchors.rightMargin: Theme.spacing.rowPaddingX
50
+ spacing: Theme.spacing.gap
51
+ Flea.Glyph { width: Theme.markSize; height: parent.height; name: root.image ? "file" : "folder-open"; color: Theme.color.foreground }
52
+ Text {
53
+ width: Math.max(0, parent.width - Theme.markSize - imageDetail.width - imageSize.width - 3 * parent.spacing)
54
+ anchors.verticalCenter: parent.verticalCenter
55
+ text: root.image ? Flash.leaf(root.image.path) : "Choose an image…"
56
+ textFormat: Text.PlainText
57
+ elide: Text.ElideRight
58
+ color: Theme.color.foreground
59
+ font { family: Theme.font.family; pixelSize: Theme.font.body }
60
+ }
61
+ Text {
62
+ id: imageDetail
63
+ width: Math.round(root.detailBoard * Theme.font.bodySmall / root.bodySmallBoard)
64
+ anchors.verticalCenter: parent.verticalCenter
65
+ text: Flash.imageDetail(root.image)
66
+ textFormat: Text.PlainText
67
+ elide: Text.ElideRight
68
+ color: root.detailInk
69
+ font { family: Theme.font.family; pixelSize: Theme.font.caption }
70
+ }
71
+ Text {
72
+ id: imageSize
73
+ width: Theme.column.size
74
+ anchors.verticalCenter: parent.verticalCenter
75
+ horizontalAlignment: Text.AlignRight
76
+ text: root.image ? Format.size(root.image.bytes) : ""
77
+ textFormat: Text.PlainText
78
+ elide: Text.ElideRight
79
+ color: root.detailInk
80
+ font { family: Theme.font.family; pixelSize: Theme.font.caption }
81
+ }
82
+ }
83
+ MouseArea {
84
+ anchors.fill: parent
85
+ acceptedButtons: Qt.LeftButton
86
+ onClicked: {
87
+ if (!root.running)
88
+ root.choose()
89
+ }
90
+ }
91
+ }
92
+ Text {
93
+ visible: root.image !== null && root.image.refused === true
94
+ x: Theme.spacing.rowPaddingX + Theme.markSize + Theme.spacing.gap
95
+ topPadding: Theme.spacing.rowPaddingY
96
+ bottomPadding: Theme.spacing.rowPaddingY
97
+ width: root.width - x - Theme.spacing.rowPaddingX
98
+ wrapMode: Text.Wrap
99
+ text: "This file is not a disk image."
100
+ color: Theme.color.muted
101
+ font { family: Theme.font.family; pixelSize: Theme.font.caption }
102
+ textFormat: Text.PlainText
103
+ }
104
+ }
@@ -0,0 +1,119 @@
1
+ import QtQuick
2
+ import "js/FlashCard.js" as FlashCard
3
+ import "js/FlashEndings.js" as FlashEndings
4
+ import "js/FlashPane.js" as FlashPane
5
+ import "js/Ops.js" as Ops
6
+
7
+ // The flash run: owns what the backend answers, so a Back mid-flash keeps answering into the pane's transfer.
8
+ Item {
9
+ id: root
10
+ required property var pane
11
+ // The running flash in Transfer.js's own shape, so the card after Back draws it unchanged.
12
+ property var transfer: Ops.emptyTransfer()
13
+ property var ending: null
14
+ // A Flash press already sent and not yet started, so a second Enter cannot double it; pendingId is its request.
15
+ property bool pressSent: false
16
+ property int pendingId: 0
17
+ property real rate: 0
18
+ property real rateAt: 0
19
+ property real rateBytes: 0
20
+ // The rate is the bytes since the last sample over at least this many seconds, so one burst never reads as the speed.
21
+ readonly property real rateWindowSeconds: 2
22
+ readonly property real msPerSecond: 1000
23
+ readonly property bool running: root.transfer.running === true
24
+
25
+ function reset() {
26
+ root.ending = null
27
+ root.pressSent = false
28
+ root.transfer = Ops.emptyTransfer()
29
+ root.rate = 0
30
+ }
31
+
32
+ // Every line the flash draws is rendered beside its fields, so Transfer.js never names the job.
33
+ function rendered(base) {
34
+ var drawn = FlashCard.render(base, root.rate)
35
+ return Object.assign({}, base, { headText: drawn.headText, fileText: drawn.fileText,
36
+ byteText: drawn.byteText, share: drawn.share, noCancel: drawn.noCancel })
37
+ }
38
+
39
+ function startTransfer(id, total, known, imageName, driveLabel, opened) {
40
+ root.pressSent = false
41
+ root.rate = 0
42
+ root.rateAt = Date.now()
43
+ root.rateBytes = 0
44
+ root.transfer = root.rendered(Object.assign(Ops.emptyTransfer(),
45
+ { id: id, flash: true, phase: "prepare", drive: driveLabel, name: imageName,
46
+ bytes: 0, total: total, known: known, permille: 0, running: true }))
47
+ root.ending = null
48
+ if (!opened) {
49
+ root.pane.transfer = root.transfer
50
+ root.pane.sticky(Ops.progressLine(root.transfer))
51
+ }
52
+ }
53
+
54
+ function noteRate(bytes) {
55
+ var now = Date.now()
56
+ var span = (now - root.rateAt) / root.msPerSecond
57
+ if (span >= root.rateWindowSeconds && bytes >= root.rateBytes) {
58
+ root.rate = (bytes - root.rateBytes) / span
59
+ root.rateAt = now
60
+ root.rateBytes = bytes
61
+ }
62
+ }
63
+
64
+ function progressTransfer(id, phase, bytes, total, permille, opened) {
65
+ if (!root.running || id !== root.transfer.id)
66
+ return
67
+ root.noteRate(bytes)
68
+ root.transfer = root.rendered(Object.assign({}, root.transfer,
69
+ { phase: phase, bytes: bytes, total: total, permille: permille }))
70
+ if (!opened) {
71
+ root.pane.transfer = root.transfer
72
+ root.pane.sticky(Ops.progressLine(root.transfer))
73
+ }
74
+ }
75
+
76
+ function finishTransfer(message, imageName, driveLabel, driveBytes, opened) {
77
+ var answer = FlashPane.doneFor({ running: root.running, transferId: root.transfer.id,
78
+ pressSent: root.pressSent, pendingId: root.pendingId }, message)
79
+ if (answer === "ignore")
80
+ return false
81
+ root.pressSent = false
82
+ // A probe refusal answers before any flashstarted, so the view asks the image row again.
83
+ if (answer === "refused" && String(message.phase || "") === "probe")
84
+ return "refused"
85
+ var ok = message.ok === true
86
+ var err = ok ? "" : String(message.err || "error")
87
+ var figures = FlashPane.endingContext(root.transfer, message)
88
+ var ctx = { image: imageName, drive: driveLabel, at: figures.at,
89
+ total: figures.total, blank: message.blank === true,
90
+ tool: message.tool || "", phase: String(message.phase || ""), driveBytes: driveBytes }
91
+ root.transfer = Ops.emptyTransfer()
92
+ root.rate = 0
93
+ if (opened) {
94
+ root.ending = FlashEndings.endingFor(err, ctx)
95
+ return true
96
+ }
97
+ FlashPane.reclaim(root.pane)
98
+ var line = FlashEndings.statusFor(err, ctx)
99
+ root.pane.message(line.text, line.isError)
100
+ return false
101
+ }
102
+
103
+ function finishEject(message, driveLabel) {
104
+ if (message.ok === true) {
105
+ root.pane.message(FlashEndings.ejectDoneLine(driveLabel), false)
106
+ return
107
+ }
108
+ if (String(message.err || "") === "busy")
109
+ root.pane.message(FlashEndings.ejectBusyLine(driveLabel), true)
110
+ else
111
+ root.pane.message(FlashEndings.ejectFailedLine(driveLabel), true)
112
+ }
113
+
114
+ Connections {
115
+ target: root.pane.backend
116
+ // A refused claim (another flash holds the slot) answers with an error and no flashdone, so the press ends here.
117
+ function onFailed(where) { if (where === "flash") root.pressSent = false }
118
+ }
119
+ }