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.
- package/LICENSE +22 -0
- package/README.md +478 -2
- package/THIRD-PARTY-NOTICES.md +29 -0
- package/demos/App.java +5 -0
- package/demos/Dockerfile +4 -0
- package/demos/Main.kt +3 -0
- package/demos/Program.cs +1 -0
- package/demos/README.md +12 -0
- package/demos/app.dart +3 -0
- package/demos/app.deb +0 -0
- package/demos/app.js +1 -0
- package/demos/backup.tar +0 -0
- package/demos/budget.xlsx +0 -0
- package/demos/build.sh +2 -0
- package/demos/bundle.zip +0 -0
- package/demos/clip.mp4 +0 -0
- package/demos/data.sqlite +0 -0
- package/demos/disk.iso +0 -0
- package/demos/engine.cpp +5 -0
- package/demos/firmware.bin +0 -0
- package/demos/flake.nix +4 -0
- package/demos/folder/inside.txt +1 -0
- package/demos/font.ttf +0 -0
- package/demos/index.html +5 -0
- package/demos/index.php +2 -0
- package/demos/init.lua +1 -0
- package/demos/letter.docx +0 -0
- package/demos/lib.rs +3 -0
- package/demos/main.c +6 -0
- package/demos/main.h +3 -0
- package/demos/math-and-diagrams.md +200 -0
- package/demos/notes.tar.gz +0 -0
- package/demos/notes.txt +3 -0
- package/demos/photo.png +0 -0
- package/demos/program +2 -0
- package/demos/report.pdf +32 -0
- package/demos/script.py +1 -0
- package/demos/server.go +7 -0
- package/demos/settings.json +4 -0
- package/demos/slides.pptx +0 -0
- package/demos/song.mp3 +0 -0
- package/demos/style.css +4 -0
- package/demos/tool.rb +1 -0
- package/demos/types.ts +2 -0
- package/docs/pele.md +23 -0
- package/docs/protocol.md +3420 -0
- package/docs/temml.md +63 -0
- package/index.js +107 -0
- package/package.json +34 -4
- package/src/archive.js +402 -0
- package/src/archiveops.js +697 -0
- package/src/backend.js +369 -0
- package/src/bulkrename.js +95 -0
- package/src/clip-host.js +76 -0
- package/src/clip.js +462 -0
- package/src/code.js +168 -0
- package/src/compare.js +74 -0
- package/src/create.js +128 -0
- package/src/dirsize.js +147 -0
- package/src/figure-svg.js +530 -0
- package/src/figure-thread.js +23 -0
- package/src/figure.js +132 -0
- package/src/find.js +55 -0
- package/src/flea.js +39 -0
- package/src/fsinfo.js +39 -0
- package/src/highlight.js +141 -0
- package/src/html.js +52 -0
- package/src/kinds.js +89 -0
- package/src/listing.js +130 -0
- package/src/markdown-html.js +317 -0
- package/src/mathml.js +186 -0
- package/src/menu.js +180 -0
- package/src/meta.js +129 -0
- package/src/office.js +810 -0
- package/src/order.js +100 -0
- package/src/peek.js +49 -0
- package/src/pele-wrapper.js +695 -0
- package/src/permissions.js +180 -0
- package/src/places.js +313 -0
- package/src/preview-language.js +10 -0
- package/src/transfer.js +669 -0
- package/src/trash-record.js +41 -0
- package/src/trash.js +210 -0
- package/src/trashbrowse.js +326 -0
- package/src/uistate.js +393 -0
- package/src/uistore.js +168 -0
- package/src/vendor/LICENSES/Apache-2.0.txt +202 -0
- package/src/vendor/LICENSES/MIT-katex-2015.txt +27 -0
- package/src/vendor/LICENSES/MIT-katex.txt +21 -0
- package/src/vendor/LICENSES/MIT-mermaid.txt +21 -0
- package/src/vendor/LICENSES/MIT-pele.txt +40 -0
- package/src/vendor/LICENSES/MIT-perseus.txt +18 -0
- package/src/vendor/LICENSES/MIT-temml.txt +21 -0
- package/src/vendor/pele.js +145 -0
- package/src/vendor/temml.mjs +14708 -0
- package/src/watch.js +98 -0
- package/src/wayland/client.js +109 -0
- package/src/wayland/protocol.js +55 -0
- package/src/wayland/protocols/ext-data-control-v1.xml +276 -0
- package/src/wayland/protocols/wayland.xml +3248 -0
- package/src/wayland/protocols/wlr-data-control-unstable-v1.xml +278 -0
- package/src/wayland/resource-io.js +6 -0
- package/src/wayland/socket-discovery.js +26 -0
- package/src/wayland/transport-posix.js +120 -0
- package/src/wayland/transport-win32.js +11 -0
- package/src/wayland/transport.js +3 -0
- package/src/wayland/win32-resources.js +80 -0
- package/src/wayland/win32-wire.js +62 -0
- package/test/archive.test.js +80 -0
- package/test/bench-markdown-scroll.mjs +190 -0
- package/test/clip-host.test.js +113 -0
- package/test/code-preview.test.js +35 -0
- package/test/compare-ui-paths.test.js +24 -0
- package/test/compare.test.js +54 -0
- package/test/delete-trash.test.js +67 -0
- package/test/dirsize.test.js +138 -0
- package/test/file-ops.test.js +241 -0
- package/test/find-contents.test.js +161 -0
- package/test/find-input.test.js +66 -0
- package/test/fixtures/pele-parity.json +1006 -0
- package/test/highlight-launcher.test.js +35 -0
- package/test/html-preview.test.js +22 -0
- package/test/input.test.js +15 -0
- package/test/keymap.test.js +26 -0
- package/test/language-icons.test.js +36 -0
- package/test/launcher.test.js +51 -0
- package/test/manual-code-scroll.mjs +28 -0
- package/test/manual-column-scroll.mjs +24 -0
- package/test/manual-compare-ui.mjs +20 -0
- package/test/manual-find-status.mjs +37 -0
- package/test/manual-html-security.mjs +23 -0
- package/test/manual-html-ui.mjs +30 -0
- package/test/manual-syntax-preview.mjs +26 -0
- package/test/manual-trash-ui.mjs +86 -0
- package/test/markdown-diagrams.test.js +93 -0
- package/test/markdown-html.test.js +105 -0
- package/test/mathml.test.js +92 -0
- package/test/menu-transfer.test.js +57 -0
- package/test/office-preview.test.js +154 -0
- package/test/pele-parity.test.js +28 -0
- package/test/places.test.js +134 -0
- package/test/preview-keys.test.js +60 -0
- package/test/preview-language.test.js +22 -0
- package/test/status-filename.test.js +20 -0
- package/test/transfer-replace-merge.test.js +187 -0
- package/test/trash-address.test.js +23 -0
- package/test/trash-view.test.js +37 -0
- package/test/trashbrowse.test.js +135 -0
- package/ui/AboutFacts.qml +78 -0
- package/ui/ArchiveCards.qml +68 -0
- package/ui/ArchiveCompressDialog.qml +378 -0
- package/ui/ArchivePasswordDialog.qml +257 -0
- package/ui/Backend.qml +771 -0
- package/ui/BulkOldNames.qml +47 -0
- package/ui/BulkRenameDialog.qml +380 -0
- package/ui/CardFrame.qml +67 -0
- package/ui/CardScroll.qml +79 -0
- package/ui/CheckBox.qml +73 -0
- package/ui/ChromeBar.qml +360 -0
- package/ui/ChromeButton.qml +131 -0
- package/ui/ChromeModes.qml +43 -0
- package/ui/CodeLines.qml +256 -0
- package/ui/CodeRefusal.qml +52 -0
- package/ui/CollideConfirm.qml +147 -0
- package/ui/CollideHost.qml +167 -0
- package/ui/ColumnPane.qml +523 -0
- package/ui/ColumnRow.qml +380 -0
- package/ui/ColumnsArea.qml +594 -0
- package/ui/ColumnsLanding.qml +147 -0
- package/ui/CompareView.qml +321 -0
- package/ui/ContextMenu.qml +743 -0
- package/ui/ConvertDialog.qml +456 -0
- package/ui/CountedWorker.qml +7 -0
- package/ui/Crumb.qml +64 -0
- package/ui/CrumbDrop.qml +25 -0
- package/ui/CsvTable.qml +394 -0
- package/ui/CursorMark.qml +41 -0
- package/ui/DefaultClaim.qml +130 -0
- package/ui/DeviceLock.qml +47 -0
- package/ui/DeviceMounts.qml +540 -0
- package/ui/DialogButton.qml +150 -0
- package/ui/DialogField.qml +147 -0
- package/ui/DialogHeader.qml +31 -0
- package/ui/DialogScrim.qml +20 -0
- package/ui/DialogTitle.qml +37 -0
- package/ui/Divider.qml +9 -0
- package/ui/DropInto.qml +126 -0
- package/ui/DropTarget.qml +35 -0
- package/ui/DropboxMark.qml +60 -0
- package/ui/EmptyState.qml +150 -0
- package/ui/EscapeHint.qml +11 -0
- package/ui/FactsTable.qml +54 -0
- package/ui/FastScrollHandler.qml +476 -0
- package/ui/FatNamesConfirm.qml +157 -0
- package/ui/Favourites.qml +143 -0
- package/ui/FigureService.qml +120 -0
- package/ui/FileDrag.qml +267 -0
- package/ui/FilterStrip.qml +133 -0
- package/ui/FitMetrics.qml +22 -0
- package/ui/FlashDriveRows.qml +137 -0
- package/ui/FlashHost.qml +72 -0
- package/ui/FlashImageRow.qml +104 -0
- package/ui/FlashRunner.qml +119 -0
- package/ui/FlashStepRow.qml +172 -0
- package/ui/FlashStrip.qml +38 -0
- package/ui/FlashView.qml +397 -0
- package/ui/FleaMark.qml +88 -0
- package/ui/FlyoutFade.qml +23 -0
- package/ui/FontPane.qml +170 -0
- package/ui/Glass.qml +114 -0
- package/ui/GlassTagger.qml +59 -0
- package/ui/Glyph.qml +64 -0
- package/ui/GlyphSolid.qml +22 -0
- package/ui/GridArea.qml +664 -0
- package/ui/GridTile.qml +325 -0
- package/ui/GvfsBridge.qml +164 -0
- package/ui/Header.qml +433 -0
- package/ui/HoverTimers.qml +39 -0
- package/ui/HtmlClip.qml +30 -0
- package/ui/HtmlPane.qml +63 -0
- package/ui/HyprlandMark.qml +45 -0
- package/ui/Ipc.qml +1005 -0
- package/ui/IpcControls.qml +7 -0
- package/ui/IpcMenuState.qml +48 -0
- package/ui/IpcPreviewState.qml +185 -0
- package/ui/JumpPath.qml +51 -0
- package/ui/KeymapSheet.qml +561 -0
- package/ui/KeymapSheetResult.qml +89 -0
- package/ui/KindStack.qml +40 -0
- package/ui/LangMark.qml +51 -0
- package/ui/LangMarkLoader.qml +26 -0
- package/ui/List.qml +480 -0
- package/ui/LoadingState.qml +54 -0
- package/ui/LocalSend.qml +56 -0
- package/ui/LocalSendMark.qml +73 -0
- package/ui/MarkdownBlockView.qml +311 -0
- package/ui/MarkdownBlocks.qml +35 -0
- package/ui/MarkdownFigure.qml +254 -0
- package/ui/MarkdownImages.qml +72 -0
- package/ui/MarkdownList.qml +81 -0
- package/ui/MarkdownMathsText.qml +97 -0
- package/ui/MarkdownPane.qml +83 -0
- package/ui/MarkdownPictures.qml +41 -0
- package/ui/MarkdownQuote.qml +52 -0
- package/ui/MarkdownRemote.qml +82 -0
- package/ui/MarkdownSource.qml +155 -0
- package/ui/MarkdownTable.qml +222 -0
- package/ui/MarkdownTableScroll.qml +64 -0
- package/ui/MarkdownTableWheel.qml +126 -0
- package/ui/MarkdownText.qml +87 -0
- package/ui/MarkdownWorker.js +132 -0
- package/ui/MatchText.qml +99 -0
- package/ui/MediaSession.qml +38 -0
- package/ui/MediaSound.qml +26 -0
- package/ui/MediaStrip.qml +191 -0
- package/ui/MediaTrack.qml +36 -0
- package/ui/MediaVolume.qml +54 -0
- package/ui/MenuActionDialog.qml +396 -0
- package/ui/MenuEdgeFade.qml +24 -0
- package/ui/MenuHost.qml +227 -0
- package/ui/MenuRow.qml +351 -0
- package/ui/MountListing.qml +100 -0
- package/ui/NetworkDialog.qml +435 -0
- package/ui/NetworkForm.qml +426 -0
- package/ui/NetworkMounts.qml +913 -0
- package/ui/NetworkPlaces.qml +127 -0
- package/ui/OpenWithDialog.qml +613 -0
- package/ui/Opener.qml +115 -0
- package/ui/Pane.qml +1296 -0
- package/ui/PaneMenuActions.qml +527 -0
- package/ui/PanePath.qml +90 -0
- package/ui/PaneRail.qml +239 -0
- package/ui/PaneStates.qml +88 -0
- package/ui/PaneSwap.qml +339 -0
- package/ui/PaneWire.qml +605 -0
- package/ui/ParkedWait.qml +9 -0
- package/ui/PathEntry.qml +186 -0
- package/ui/PathJump.qml +400 -0
- package/ui/PdfViewer.qml +297 -0
- package/ui/PermissionsDialog.qml +658 -0
- package/ui/PermissionsHeadings.qml +31 -0
- package/ui/PhoneMounts.qml +67 -0
- package/ui/PickerAnswers.qml +75 -0
- package/ui/PickerBox.qml +26 -0
- package/ui/PickerChrome.qml +295 -0
- package/ui/PickerFilter.qml +97 -0
- package/ui/PickerGrid.qml +308 -0
- package/ui/PickerHeader.qml +28 -0
- package/ui/PickerLifecycle.qml +27 -0
- package/ui/PickerList.qml +218 -0
- package/ui/PickerListing.qml +149 -0
- package/ui/PickerPathBar.qml +127 -0
- package/ui/PickerPlaces.qml +189 -0
- package/ui/PickerRecent.qml +92 -0
- package/ui/PickerSave.qml +101 -0
- package/ui/PickerSelection.qml +155 -0
- package/ui/PickerWindow.qml +846 -0
- package/ui/PowerSectorsReader.qml +10 -0
- package/ui/PrebuildDriver.qml +146 -0
- package/ui/Preview.qml +1004 -0
- package/ui/PreviewAnimation.qml +24 -0
- package/ui/PreviewArchive.qml +66 -0
- package/ui/PreviewColumn.qml +551 -0
- package/ui/PreviewEdge.qml +63 -0
- package/ui/PreviewFacts.qml +30 -0
- package/ui/PreviewFactsLine.qml +34 -0
- package/ui/PreviewHtml.qml +233 -0
- package/ui/PreviewImage.qml +253 -0
- package/ui/PreviewImagePan.qml +13 -0
- package/ui/PreviewImageSharp.qml +32 -0
- package/ui/PreviewLines.qml +106 -0
- package/ui/PreviewMarkdown.qml +706 -0
- package/ui/PreviewMedia.qml +250 -0
- package/ui/PreviewPdf.qml +482 -0
- package/ui/PreviewScroll.qml +201 -0
- package/ui/PreviewSwap.qml +335 -0
- package/ui/PreviewText.qml +149 -0
- package/ui/ProtocolChip.qml +18 -0
- package/ui/QuickLookArchive.qml +38 -0
- package/ui/QuickLookBar.qml +103 -0
- package/ui/QuickLookPrepare.qml +355 -0
- package/ui/QuickLookSwap.qml +10 -0
- package/ui/QuickLookWarm.qml +65 -0
- package/ui/RailDrop.qml +155 -0
- package/ui/RailHeading.qml +19 -0
- package/ui/RailPlaces.qml +38 -0
- package/ui/RailTrashRow.qml +67 -0
- package/ui/RenameField.qml +353 -0
- package/ui/RendererRetry.qml +11 -0
- package/ui/ResizeHandle.qml +52 -0
- package/ui/Reveal.qml +54 -0
- package/ui/Row.qml +476 -0
- package/ui/RowDrag.qml +213 -0
- package/ui/RowDropTarget.qml +27 -0
- package/ui/RunCard.qml +286 -0
- package/ui/Scripts.qml +65 -0
- package/ui/SearchStrip.qml +232 -0
- package/ui/SelectionBand.qml +140 -0
- package/ui/SelectionPreview.qml +370 -0
- package/ui/SettingsFavourite.qml +122 -0
- package/ui/SettingsGroup.qml +96 -0
- package/ui/SettingsHint.qml +12 -0
- package/ui/SettingsMetrics.qml +29 -0
- package/ui/SettingsPane.qml +178 -0
- package/ui/SettingsPanel.qml +547 -0
- package/ui/SettingsRail.qml +128 -0
- package/ui/SettingsRow.qml +409 -0
- package/ui/SettingsRuler.qml +85 -0
- package/ui/SettingsSegment.qml +85 -0
- package/ui/ShareBrowser.qml +113 -0
- package/ui/ShareLink.qml +67 -0
- package/ui/ShelfPins.qml +101 -0
- package/ui/Sidebar.qml +732 -0
- package/ui/SidebarRow.qml +358 -0
- package/ui/Spinner.qml +60 -0
- package/ui/StableModel.qml +89 -0
- package/ui/StateMessage.qml +84 -0
- package/ui/StatusBar.qml +512 -0
- package/ui/StatusFileName.qml +27 -0
- package/ui/TabBar.qml +673 -0
- package/ui/TabDragGeometry.qml +60 -0
- package/ui/TagMenuMark.qml +52 -0
- package/ui/TagRailSection.qml +53 -0
- package/ui/TagSlot.qml +40 -0
- package/ui/TagState.qml +150 -0
- package/ui/TagSwatch.qml +28 -0
- package/ui/Taildrop.qml +86 -0
- package/ui/TailscaleMark.qml +50 -0
- package/ui/Theme.qml +460 -0
- package/ui/ThemeColors.qml +43 -0
- package/ui/TransferCard.qml +239 -0
- package/ui/TrashConfirm.qml +129 -0
- package/ui/TrashDropHandler.qml +11 -0
- package/ui/TrashHost.qml +202 -0
- package/ui/TrashMonitor.qml +30 -0
- package/ui/TrashToolbar.qml +19 -0
- package/ui/TrashView.qml +492 -0
- package/ui/UnlockDialog.qml +450 -0
- package/ui/UnlockHost.qml +206 -0
- package/ui/UpdateCheck.qml +97 -0
- package/ui/UserDirs.qml +25 -0
- package/ui/ViewState.qml +565 -0
- package/ui/ViewportScrollBar.qml +195 -0
- package/ui/ViewportScrollBars.qml +25 -0
- package/ui/WebPreview.qml +33 -0
- package/ui/WebPreviewView.qml +26 -0
- package/ui/WindowBody.qml +827 -0
- package/ui/WindowDrag.qml +35 -0
- package/ui/boot/Commons/AudioNodes.qml +50 -0
- package/ui/boot/Commons/AudioNodesModel.js +96 -0
- package/ui/boot/Commons/Border.qml +243 -0
- package/ui/boot/Commons/BorderGeometry.js +373 -0
- package/ui/boot/Commons/Color.qml +258 -0
- package/ui/boot/Commons/I18n.qml +118 -0
- package/ui/boot/Commons/InputDevices.qml +112 -0
- package/ui/boot/Commons/InputMethodState.qml +38 -0
- package/ui/boot/Commons/IpcRegistry.qml +77 -0
- package/ui/boot/Commons/Numbers.js +19 -0
- package/ui/boot/Commons/Plural.js +91 -0
- package/ui/boot/Commons/ShellIpc.qml +12 -0
- package/ui/boot/Commons/Style.qml +561 -0
- package/ui/boot/Commons/Translations.qml +100 -0
- package/ui/boot/Commons/UntypedInput.qml +152 -0
- package/ui/boot/Commons/Util.qml +188 -0
- package/ui/boot/Commons/qmldir +13 -0
- package/ui/boot/LICENSE-omarchy +20 -0
- package/ui/boot/Ui/BackgroundMedia.qml +49 -0
- package/ui/boot/Ui/BarIconButton.qml +106 -0
- package/ui/boot/Ui/BarIconContent.qml +38 -0
- package/ui/boot/Ui/BarIndicator.qml +53 -0
- package/ui/boot/Ui/BarWidget.qml +50 -0
- package/ui/boot/Ui/BorderOverlay.qml +54 -0
- package/ui/boot/Ui/BorderSurface.qml +40 -0
- package/ui/boot/Ui/Button.qml +224 -0
- package/ui/boot/Ui/ButtonGroup.qml +131 -0
- package/ui/boot/Ui/ConfirmDialog.qml +134 -0
- package/ui/boot/Ui/CursorSurface.qml +42 -0
- package/ui/boot/Ui/Dropdown.qml +245 -0
- package/ui/boot/Ui/FilterInput.qml +26 -0
- package/ui/boot/Ui/IconContentBounds.qml +141 -0
- package/ui/boot/Ui/KeyboardPanel.qml +453 -0
- package/ui/boot/Ui/MultiSelect.qml +624 -0
- package/ui/boot/Ui/NumberField.qml +86 -0
- package/ui/boot/Ui/OpticalGlyph.qml +68 -0
- package/ui/boot/Ui/OverlayWindow.qml +102 -0
- package/ui/boot/Ui/Panel.qml +60 -0
- package/ui/boot/Ui/PanelActionButton.qml +105 -0
- package/ui/boot/Ui/PanelController.qml +16 -0
- package/ui/boot/Ui/PanelHero.qml +112 -0
- package/ui/boot/Ui/PanelKeyCatcher.qml +100 -0
- package/ui/boot/Ui/PanelSectionHeader.qml +31 -0
- package/ui/boot/Ui/PanelSeparator.qml +19 -0
- package/ui/boot/Ui/PanelSlider.qml +156 -0
- package/ui/boot/Ui/PanelToolTip.qml +50 -0
- package/ui/boot/Ui/PluginBarApi.qml +89 -0
- package/ui/boot/Ui/PointerMoveGate.qml +54 -0
- package/ui/boot/Ui/PopupCard.qml +181 -0
- package/ui/boot/Ui/ScreenMoveRemap.qml +43 -0
- package/ui/boot/Ui/SearchableDropdown.qml +354 -0
- package/ui/boot/Ui/SizedImage.qml +125 -0
- package/ui/boot/Ui/SpeedTestOverlay.qml +412 -0
- package/ui/boot/Ui/TextField.qml +58 -0
- package/ui/boot/Ui/Toggle.qml +118 -0
- package/ui/boot/Ui/ToggleSwitch.qml +115 -0
- package/ui/boot/Ui/WidgetButton.qml +172 -0
- package/ui/boot/Ui/qmldir +41 -0
- package/ui/boot/fleatab.qml +50 -0
- package/ui/boot/picker.qml +39 -0
- package/ui/boot/shell.qml +122 -0
- package/ui/boot/tabtearoff.qml +51 -0
- package/ui/js/Anchor.js +379 -0
- package/ui/js/AnchorHold.js +162 -0
- package/ui/js/Archive.js +157 -0
- package/ui/js/ArchiveCard.js +44 -0
- package/ui/js/ArchiveOps.js +44 -0
- package/ui/js/BackReturn.js +118 -0
- package/ui/js/BulkRename.js +100 -0
- package/ui/js/Buttons.js +54 -0
- package/ui/js/ChromeKeys.js +116 -0
- package/ui/js/ClipMarks.js +73 -0
- package/ui/js/ClipSelection.js +67 -0
- package/ui/js/Clipboard.js +179 -0
- package/ui/js/Cloud.js +97 -0
- package/ui/js/CodeRuns.js +72 -0
- package/ui/js/Collide.js +212 -0
- package/ui/js/ColumnFit.js +28 -0
- package/ui/js/ColumnMenu.js +111 -0
- package/ui/js/Columns.js +298 -0
- package/ui/js/ColumnsCarry.js +103 -0
- package/ui/js/Compare.js +74 -0
- package/ui/js/Contrast.js +157 -0
- package/ui/js/ControlReader.js +42 -0
- package/ui/js/Convert.js +52 -0
- package/ui/js/CopyAs.js +52 -0
- package/ui/js/Crumbs.js +178 -0
- package/ui/js/Csv.js +231 -0
- package/ui/js/Density.js +44 -0
- package/ui/js/Devices.js +440 -0
- package/ui/js/DirSizes.js +180 -0
- package/ui/js/Drag.js +364 -0
- package/ui/js/DragOut.js +166 -0
- package/ui/js/DropDev.js +52 -0
- package/ui/js/Dropbox.js +41 -0
- package/ui/js/Eject.js +217 -0
- package/ui/js/Errors.js +188 -0
- package/ui/js/ExtThumbs.js +115 -0
- package/ui/js/Facts.js +402 -0
- package/ui/js/FigureDate.js +14 -0
- package/ui/js/Filter.js +285 -0
- package/ui/js/Find.js +46 -0
- package/ui/js/Flash.js +184 -0
- package/ui/js/FlashCard.js +79 -0
- package/ui/js/FlashEndings.js +125 -0
- package/ui/js/FlashPane.js +116 -0
- package/ui/js/FleaBin.js +12 -0
- package/ui/js/Focus.js +502 -0
- package/ui/js/FolderSorts.js +108 -0
- package/ui/js/FolderViews.js +44 -0
- package/ui/js/Format.js +305 -0
- package/ui/js/Fuzzy.js +141 -0
- package/ui/js/GlassTag.js +72 -0
- package/ui/js/Grid.js +33 -0
- package/ui/js/GridGeometry.js +90 -0
- package/ui/js/GridNames.js +153 -0
- package/ui/js/GvfsBridge.js +200 -0
- package/ui/js/HostClipboard.js +29 -0
- package/ui/js/Icons.js +218 -0
- package/ui/js/Input.js +50 -0
- package/ui/js/Jump.js +200 -0
- package/ui/js/KeyName.js +64 -0
- package/ui/js/Keymap.js +401 -0
- package/ui/js/Kinds.js +164 -0
- package/ui/js/LICENSES/ISC-lucide.txt +43 -0
- package/ui/js/LangMarkPaths.js +47 -0
- package/ui/js/LangMarks.js +120 -0
- package/ui/js/Lists.js +11 -0
- package/ui/js/LocalSend.js +39 -0
- package/ui/js/LockedMenu.js +63 -0
- package/ui/js/MakeDefault.js +186 -0
- package/ui/js/MarkBox.js +7 -0
- package/ui/js/Markdown.js +119 -0
- package/ui/js/MarkdownLists.js +86 -0
- package/ui/js/MarkdownMaths.js +58 -0
- package/ui/js/MarkdownPictures.js +32 -0
- package/ui/js/MarkdownPrepared.js +139 -0
- package/ui/js/MarkdownTableFit.js +34 -0
- package/ui/js/Marks.js +148 -0
- package/ui/js/Marquee.js +96 -0
- package/ui/js/Match.js +93 -0
- package/ui/js/Material.js +109 -0
- package/ui/js/MdBlocks.js +437 -0
- package/ui/js/MdBreak.js +71 -0
- package/ui/js/MdChunks.js +70 -0
- package/ui/js/MdContainer.js +137 -0
- package/ui/js/MdDocument.js +337 -0
- package/ui/js/MdEmph.js +97 -0
- package/ui/js/MdEntity.js +108 -0
- package/ui/js/MdEntityTable.js +223 -0
- package/ui/js/MdEscape.js +59 -0
- package/ui/js/MdFront.js +37 -0
- package/ui/js/MdHold.js +32 -0
- package/ui/js/MdHtml.js +307 -0
- package/ui/js/MdHtmlBlock.js +290 -0
- package/ui/js/MdHtmlHeading.js +53 -0
- package/ui/js/MdHtmlImage.js +179 -0
- package/ui/js/MdInline.js +154 -0
- package/ui/js/MdItems.js +212 -0
- package/ui/js/MdLeaf.js +309 -0
- package/ui/js/MdLink.js +196 -0
- package/ui/js/MdMath.js +67 -0
- package/ui/js/MdParagraphs.js +138 -0
- package/ui/js/MdRefs.js +232 -0
- package/ui/js/MdResolve.js +226 -0
- package/ui/js/MdRun.js +300 -0
- package/ui/js/MdUrl.js +226 -0
- package/ui/js/Menu.js +514 -0
- package/ui/js/MenuContext.js +85 -0
- package/ui/js/MenuFit.js +13 -0
- package/ui/js/MenuRefresh.js +74 -0
- package/ui/js/MenuWheel.js +35 -0
- package/ui/js/Messages.js +186 -0
- package/ui/js/Motion.js +16 -0
- package/ui/js/Mounts.js +320 -0
- package/ui/js/MouseNav.js +13 -0
- package/ui/js/Nav.js +329 -0
- package/ui/js/NetFs.js +26 -0
- package/ui/js/OpenWith.js +83 -0
- package/ui/js/Ops.js +585 -0
- package/ui/js/Palette.js +33 -0
- package/ui/js/PathBar.js +260 -0
- package/ui/js/Permissions.js +179 -0
- package/ui/js/Phones.js +112 -0
- package/ui/js/Picker.js +353 -0
- package/ui/js/PlaceMenu.js +96 -0
- package/ui/js/Places.js +265 -0
- package/ui/js/PreviewAsk.js +21 -0
- package/ui/js/PreviewKeys.js +155 -0
- package/ui/js/PreviewSettle.js +29 -0
- package/ui/js/PreviewSwap.js +101 -0
- package/ui/js/PropertyFacts.js +144 -0
- package/ui/js/Protocols.js +296 -0
- package/ui/js/QuickLookKinds.js +27 -0
- package/ui/js/QuickLookRect.js +24 -0
- package/ui/js/RailDrop.js +51 -0
- package/ui/js/RailKeys.js +87 -0
- package/ui/js/RailMenu.js +133 -0
- package/ui/js/Recent.js +135 -0
- package/ui/js/RecentMode.js +156 -0
- package/ui/js/Reload.js +60 -0
- package/ui/js/Renderer.js +9 -0
- package/ui/js/RunFile.js +143 -0
- package/ui/js/Scripts.js +28 -0
- package/ui/js/Scroll.js +304 -0
- package/ui/js/ScrollOff.js +69 -0
- package/ui/js/Search.js +478 -0
- package/ui/js/Selection.js +97 -0
- package/ui/js/Settings.js +476 -0
- package/ui/js/SettingsAbout.js +97 -0
- package/ui/js/SettingsShelf.js +52 -0
- package/ui/js/SheetKeys.js +42 -0
- package/ui/js/SheetQuery.js +281 -0
- package/ui/js/ShelfPile.js +27 -0
- package/ui/js/SlowClick.js +53 -0
- package/ui/js/SlowOp.js +6 -0
- package/ui/js/Sort.js +134 -0
- package/ui/js/Startup.js +63 -0
- package/ui/js/StateWords.js +17 -0
- package/ui/js/Status.js +238 -0
- package/ui/js/Swap.js +166 -0
- package/ui/js/TabMove.js +39 -0
- package/ui/js/Tabs.js +736 -0
- package/ui/js/Tags.js +134 -0
- package/ui/js/Taildrop.js +128 -0
- package/ui/js/Tap.js +174 -0
- package/ui/js/TextSize.js +107 -0
- package/ui/js/Thumbs.js +158 -0
- package/ui/js/Transfer.js +172 -0
- package/ui/js/Trash.js +81 -0
- package/ui/js/TrashDates.js +47 -0
- package/ui/js/TrashDrop.js +64 -0
- package/ui/js/UiState.js +438 -0
- package/ui/js/Unlock.js +152 -0
- package/ui/js/Update.js +130 -0
- package/ui/js/UserDirs.js +56 -0
- 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
|
+
}
|
package/ui/FlashHost.qml
ADDED
|
@@ -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
|
+
}
|