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
package/ui/Sidebar.qml
ADDED
|
@@ -0,0 +1,732 @@
|
|
|
1
|
+
import QtQuick
|
|
2
|
+
import Quickshell
|
|
3
|
+
import Quickshell.Io
|
|
4
|
+
import qs.Commons
|
|
5
|
+
import "." as Flea
|
|
6
|
+
import "js/Eject.js" as Eject
|
|
7
|
+
import "js/Mounts.js" as Mounts
|
|
8
|
+
import "js/Places.js" as Places
|
|
9
|
+
import "js/PlaceMenu.js" as PlaceMenu
|
|
10
|
+
import "js/RailMenu.js" as RailMenu
|
|
11
|
+
import "js/RailKeys.js" as RailKeys
|
|
12
|
+
|
|
13
|
+
// Places, Favorites, Network and Devices share one flat cursor in visual order.
|
|
14
|
+
Item {
|
|
15
|
+
id: root
|
|
16
|
+
|
|
17
|
+
property bool focused: false
|
|
18
|
+
property var backend: null
|
|
19
|
+
property Item navigationPane: null
|
|
20
|
+
property bool trashActive: false
|
|
21
|
+
// Set by Enter on a row that mounts first, so the open that lands afterwards takes focus into the folder.
|
|
22
|
+
property bool focusOnOpen: false
|
|
23
|
+
// Right Arrow from a row that releases puts the keyboard on its eject mark; a move, a lost focus or a vanished mark ends its frame.
|
|
24
|
+
property bool markFocused: false
|
|
25
|
+
// A pointer press on a focused rail returns the highlight to the current place until the next rail key.
|
|
26
|
+
property bool pointerFocus: false
|
|
27
|
+
onFocusedChanged: if (!root.focused) { root.markFocused = false; root.pointerFocus = false }
|
|
28
|
+
// ui/Pane.qml's one ui/ContextMenu.qml, handed in rather than built here: a second instance in
|
|
29
|
+
// this tree took the keyboard away from the list, see ui/SidebarRow.qml's own note.
|
|
30
|
+
property var menu: null
|
|
31
|
+
property int cursorIndex: 0
|
|
32
|
+
property var cursorEntries: []
|
|
33
|
+
// The row that holds what the rail pane shows. It is settled only once no listing is out, so it moves in the frame the listing swaps.
|
|
34
|
+
property int litIndex: -1
|
|
35
|
+
// The menu sets cursorIndex on open; the keyboard highlight stays off while that menu is open.
|
|
36
|
+
readonly property bool cursorDrawn: RailKeys.cursorDrawn(root.focused, root.menu && root.menu.opened && root.menu.forRail, root.pointerFocus)
|
|
37
|
+
readonly property int highlightedIndex: root.cursorDrawn ? root.cursorIndex : root.litIndex
|
|
38
|
+
function settleLit() {
|
|
39
|
+
var pane = root.navigationPane
|
|
40
|
+
if (pane === null || pane.listInFlight)
|
|
41
|
+
return
|
|
42
|
+
root.litIndex = Places.heldBy(root.entries, pane.path, Places.litView(pane.trash.opened, pane.recentMode, pane.searchMode, pane.swap.answeredQuery, pane.pathAlias))
|
|
43
|
+
}
|
|
44
|
+
onNavigationPaneChanged: root.settleLit()
|
|
45
|
+
Connections {
|
|
46
|
+
target: root.navigationPane
|
|
47
|
+
function onPathChanged() { root.settleLit() }
|
|
48
|
+
function onRecentModeChanged() { root.settleLit() }
|
|
49
|
+
function onSearchModeChanged() { root.settleLit() }
|
|
50
|
+
function onListInFlightChanged() { root.settleLit() }
|
|
51
|
+
}
|
|
52
|
+
Connections {
|
|
53
|
+
target: root.navigationPane ? root.navigationPane.trash : null
|
|
54
|
+
function onOpenedChanged() { root.settleLit() }
|
|
55
|
+
}
|
|
56
|
+
Connections {
|
|
57
|
+
target: root.navigationPane ? root.navigationPane.swap : null
|
|
58
|
+
function onAnsweredQueryChanged() { root.settleLit() }
|
|
59
|
+
}
|
|
60
|
+
readonly property var placesState: ViewState.state.places || ({})
|
|
61
|
+
readonly property var userFavouriteEntries: RailPlaces.favouriteEntries
|
|
62
|
+
readonly property var homeEntries: RailPlaces.homeEntries
|
|
63
|
+
// Recent sits under Home and carries a location token.
|
|
64
|
+
readonly property var homeLead: root.homeEntries.slice(0, 1)
|
|
65
|
+
readonly property var homeRest: root.homeEntries.slice(1)
|
|
66
|
+
readonly property var recentEntries: RailPlaces.recentEntries
|
|
67
|
+
readonly property var placesEntries: root.homeLead.concat(root.recentEntries, root.homeRest, root.trashEntries, root.userFavouriteEntries, root.tagRows)
|
|
68
|
+
// The TAGS section (ui/TagRailSection.qml) is built once the setting is on and a tag is in use, since it ships off; its rows end the places group.
|
|
69
|
+
property var tagSection: null
|
|
70
|
+
readonly property var tagRows: root.tagSection !== null && root.placesState.showTags === true ? root.tagSection.entries : []
|
|
71
|
+
readonly property bool tagsListed: root.placesState.showTags === true && root.navigationPane !== null && root.navigationPane.tagState !== null
|
|
72
|
+
&& Object.keys(root.navigationPane.tagState.inUse).length > 0
|
|
73
|
+
onTagsListedChanged: {
|
|
74
|
+
if (!root.tagsListed || root.tagSection !== null) return
|
|
75
|
+
root.tagSection = Qt.createComponent("TagRailSection.qml").createObject(netGap, { sidebar: root })
|
|
76
|
+
}
|
|
77
|
+
readonly property int trashCount: trashMonitor.count
|
|
78
|
+
signal trashChanged()
|
|
79
|
+
function refreshTrash() { trashMonitor.refresh() }
|
|
80
|
+
TrashMonitor {
|
|
81
|
+
id: trashMonitor
|
|
82
|
+
backend: root.navigationPane ? root.navigationPane.backend : null
|
|
83
|
+
watching: root.trashActive || root.placesState.showTrash !== false
|
|
84
|
+
onChanged: root.trashChanged()
|
|
85
|
+
// A background poll the operator never asked for must not take the status bar: the count is
|
|
86
|
+
// read for the rail Trash menu even with the badge off, so only a shown count reports it.
|
|
87
|
+
onFailed: function(text) { if (root.trashActive || root.placesState.trashCount === true) root.message(text, true) }
|
|
88
|
+
}
|
|
89
|
+
readonly property var trashEntries: RailPlaces.trashEntries.map(function (entry) {
|
|
90
|
+
return Object.assign({}, entry, { count: root.trashCount })
|
|
91
|
+
})
|
|
92
|
+
signal trashRequested()
|
|
93
|
+
// Folder drops share one receiver below the rows; Trash's own area answers above it.
|
|
94
|
+
RailDrop { id: fileDrop; sidebar: root; viewport: scroller }
|
|
95
|
+
|
|
96
|
+
// The saved place an Edit is rewriting, "" when none is; ui/js/RailMenu.js editPlace sets it.
|
|
97
|
+
property string editingPlace: ""
|
|
98
|
+
// And the request that Edit's own attempt went out with, so no other mount answers for it.
|
|
99
|
+
property string editingRequest: ""
|
|
100
|
+
// PaneRail injects the window-long host, so hiding the rail preserves mounts, waits and dialog answers.
|
|
101
|
+
property var service: null
|
|
102
|
+
readonly property var networkEntries: root.placesState.showNetwork === false || !root.railGate.showNetwork || !root.service ? [] : root.service.entries
|
|
103
|
+
// The poll rebinds its delegates in place, so a rename left standing would edit a different share.
|
|
104
|
+
onNetworkEntriesChanged: root.cancelRename()
|
|
105
|
+
// Phones ride the DEVICES group behind the block devices: a plugged phone is a device to the person holding it, whatever transport gvfs reaches it over.
|
|
106
|
+
readonly property var deviceEntries: root.placesState.showDevices === false || !root.railGate.showDevices ? [] : devices.entries.concat(phones.entries, root.volumeEntries)
|
|
107
|
+
// flea-qml: the drives the backend found by looking close the group: every root a path can
|
|
108
|
+
// start from and what is mounted where drives are mounted, on systems lsblk says nothing about.
|
|
109
|
+
readonly property var volumeEntries: Places.volumeEntries(RailPlaces.probedVolumes, devices.entries)
|
|
110
|
+
// The eject chain's guard state, read fresh at ipc time, so a failed eject names its guard.
|
|
111
|
+
function ejectChainState() { return devices.ejectState() }
|
|
112
|
+
// A release in flight, which PaneRail holds the rail open for.
|
|
113
|
+
readonly property bool releasing: devices.releasing
|
|
114
|
+
// False parks the DEVICES poll; PaneRail drops it while an auto-hide rail is withdrawn, and a reveal polls at once.
|
|
115
|
+
property bool polling: true
|
|
116
|
+
function pollDevices() { devices.poll() }
|
|
117
|
+
// flea-qml: the backend looks for places again every five seconds only while a rail asks it
|
|
118
|
+
// to (src/places.js), so a parked or unloaded rail takes its request back.
|
|
119
|
+
property var placesWatcher: null
|
|
120
|
+
function watchPlaces(shown) {
|
|
121
|
+
var want = shown && root.polling ? root.backend : null
|
|
122
|
+
if (want === root.placesWatcher) return
|
|
123
|
+
if (root.placesWatcher) root.placesWatcher.send({ c: "places", watch: false })
|
|
124
|
+
root.placesWatcher = want
|
|
125
|
+
if (want) want.send({ c: "places", watch: true })
|
|
126
|
+
}
|
|
127
|
+
onPollingChanged: root.watchPlaces(true)
|
|
128
|
+
onBackendChanged: root.watchPlaces(true)
|
|
129
|
+
readonly property var entries: root.placesEntries.concat(root.networkEntries, root.deviceEntries)
|
|
130
|
+
|
|
131
|
+
// The rail lands in one step by gating the entries themselves, so cursor, IPC and menus match only drawn rows.
|
|
132
|
+
readonly property int railSettleMs: 800
|
|
133
|
+
property bool railDeadlineElapsed: false
|
|
134
|
+
property bool bookmarksReady: false
|
|
135
|
+
// Favourite-relative insertion boundary, count past the last row, -1 when idle; a rebuild clears it.
|
|
136
|
+
property int reorderLine: -1
|
|
137
|
+
readonly property var railGate: Mounts.railGroupsReady(root.bookmarksReady && root.service !== null && root.service.listingAnswered && root.service.dropboxAnswered, devices.firstAnswered && phones.firstDone, root.railDeadlineElapsed ? root.railSettleMs : 0, root.railSettleMs)
|
|
138
|
+
Timer { interval: root.railSettleMs; running: true; repeat: false; onTriggered: root.railDeadlineElapsed = true }
|
|
139
|
+
|
|
140
|
+
// Reconcile only the aggregate; evaluating entries from a group's change handler re-enters its binding.
|
|
141
|
+
onEntriesChanged: {
|
|
142
|
+
root.reorderLine = -1
|
|
143
|
+
var next = Places.railCursorAfter(root.cursorEntries, root.entries, root.cursorIndex)
|
|
144
|
+
var lit = Places.railCursorAfter(root.cursorEntries, root.entries, root.litIndex)
|
|
145
|
+
if (root.renamingIndex >= 0
|
|
146
|
+
&& Places.railCursorAfter(root.cursorEntries, root.entries, root.renamingIndex) !== root.renamingIndex)
|
|
147
|
+
root.cancelRename()
|
|
148
|
+
root.cursorEntries = root.entries
|
|
149
|
+
root.cursorIndex = next
|
|
150
|
+
// A listing still out keeps its row through the rebuild; an idle pane re-reads it.
|
|
151
|
+
root.litIndex = lit
|
|
152
|
+
root.settleLit()
|
|
153
|
+
root.markFocused = root.markFocused && Eject.releasable(root.entries[next])
|
|
154
|
+
availability.restart()
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
signal opened(string path)
|
|
158
|
+
// A locked LUKS row opens the unlock dialog instead of running gio mount.
|
|
159
|
+
signal unlockRequested(string device, string label, double size, string fstype)
|
|
160
|
+
// Recent answers bounded newest-first history paths, which the pane opens through listpaths.
|
|
161
|
+
signal recentRequested(var paths, var requester, var visits)
|
|
162
|
+
signal addRequested()
|
|
163
|
+
// The rail's Edit row asks the window to open the dialog over the saved place.
|
|
164
|
+
signal editRequested(string uri, string label, string password, string reason, bool failedConnect, var origin)
|
|
165
|
+
signal message(string text, bool isError)
|
|
166
|
+
signal operationResult(string headline, string detail, bool isError)
|
|
167
|
+
signal forgetMessage(string text)
|
|
168
|
+
|
|
169
|
+
// The entry index mid-rename, or -1; ui/SidebarRow.qml swaps its Text for a field on it, and ui/Pane.qml holds its keys off while it stands.
|
|
170
|
+
property int renamingIndex: -1
|
|
171
|
+
// Fires once, on both commit and cancel, so ui/Pane.qml has one place to hand focus back.
|
|
172
|
+
signal renameFinished()
|
|
173
|
+
// Any press inside the rail, so an overlay rail can take the keyboard though a row or the Flickable below holds the grab: the handler's item is above every child.
|
|
174
|
+
signal pressed()
|
|
175
|
+
|
|
176
|
+
// Sized in characters, because a monospace makes that exact where a pixel constant would be an accident.
|
|
177
|
+
readonly property int widthChars: 18
|
|
178
|
+
// The mark and its gap count too, because ui/SidebarRow.qml draws them before the label: without them an 18-character entry elided at 15.
|
|
179
|
+
implicitWidth: Places.sidebarWidth(root.placesState.sidebarWidth)
|
|
180
|
+
|
|
181
|
+
TextMetrics {
|
|
182
|
+
id: metrics
|
|
183
|
+
font.family: Theme.font.family
|
|
184
|
+
font.pixelSize: Theme.font.body
|
|
185
|
+
text: "0"
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
FileView {
|
|
189
|
+
id: bookmarksFile
|
|
190
|
+
path: Quickshell.env("HOME") + "/.config/gtk-3.0/bookmarks"
|
|
191
|
+
watchChanges: true
|
|
192
|
+
printErrors: false
|
|
193
|
+
onFileChanged: reload()
|
|
194
|
+
onLoaded: { root.bookmarksReady = true; root.pushBookmarks() }
|
|
195
|
+
onLoadFailed: { root.bookmarksReady = true; root.pushBookmarks() }
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// The host keeps its own copy of this text: it outlives this rail, so a rail unload
|
|
199
|
+
// mid-mount leaves the mount's labels and dedup exactly where they were. Pushed only
|
|
200
|
+
// after the FileView loaded, so a reveal never blanks the host with an unread "".
|
|
201
|
+
function pushBookmarks() {
|
|
202
|
+
if (!root.bookmarksReady || !root.service) return
|
|
203
|
+
root.service.bookmarksText = bookmarksFile.text()
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// The window-long poll runs while a rail is loaded; arrival waits until the pane's overlay parent is bound.
|
|
207
|
+
Component.onCompleted: { Qt.callLater(root.meetHost); root.watchPlaces(true) }
|
|
208
|
+
function meetHost() { root.arrive() } // never builds the host: ui/WindowBody.qml orders it after the first rows
|
|
209
|
+
// Arrival counts whenever the service appears, so a host built after this rail still starts the poll.
|
|
210
|
+
property bool arrived: false
|
|
211
|
+
function arrive() { if (root.arrived || !root.service) return; root.arrived = true; root.service.railArrived() }
|
|
212
|
+
onServiceChanged: { root.arrive(); root.pushBookmarks() }
|
|
213
|
+
// Departure hands the timer back to a flight, if any, and the last listing stands while it is off.
|
|
214
|
+
Component.onDestruction: { if (root.service && root.arrived) root.service.railLeft(); root.watchPlaces(false) }
|
|
215
|
+
|
|
216
|
+
// The desktop's own history, read and never written, kept across opens.
|
|
217
|
+
property var recentPaths: []
|
|
218
|
+
property var recentVisits: ({})
|
|
219
|
+
property bool recentKept: false
|
|
220
|
+
property bool recentReading: false
|
|
221
|
+
property int recentChanges: 0
|
|
222
|
+
property int recentReadAt: -1
|
|
223
|
+
// Every asker waiting on the read in flight, null meaning the rail pane itself.
|
|
224
|
+
property var recentRequesters: []
|
|
225
|
+
// How many times the history has been parsed; the seam reads it the way it reads the jump's.
|
|
226
|
+
property int recentReads: 0
|
|
227
|
+
function readRecent(requester) {
|
|
228
|
+
// One read at a time: every asker waits on it, so each pane opens once it lands.
|
|
229
|
+
if (root.recentReading) {
|
|
230
|
+
root.recentRequesters = recentReader.item.joinRequesters(root.recentRequesters, requester)
|
|
231
|
+
return
|
|
232
|
+
}
|
|
233
|
+
if (root.recentKept && root.recentReadAt === root.recentChanges) {
|
|
234
|
+
root.recentRequested(root.recentPaths, requester || null, root.recentVisits)
|
|
235
|
+
return
|
|
236
|
+
}
|
|
237
|
+
// Build the helper with the reader, only after an uncached Recent action.
|
|
238
|
+
recentReader.active = true
|
|
239
|
+
root.recentRequesters = recentReader.item.joinRequesters([], requester)
|
|
240
|
+
root.recentReading = true
|
|
241
|
+
root.recentReadAt = root.recentChanges
|
|
242
|
+
recentWatcher.path = recentReader.item.file
|
|
243
|
+
recentReader.item.refresh()
|
|
244
|
+
}
|
|
245
|
+
// Watching only: it never loads the file, and it reports a rename over it, a delete and a re-create alike.
|
|
246
|
+
FileView {
|
|
247
|
+
id: recentWatcher
|
|
248
|
+
preload: false
|
|
249
|
+
watchChanges: true
|
|
250
|
+
onFileChanged: root.recentChanges += 1
|
|
251
|
+
}
|
|
252
|
+
// The history reader and its helpers load on a Recent action, then drop after the read.
|
|
253
|
+
Loader {
|
|
254
|
+
id: recentReader
|
|
255
|
+
active: false
|
|
256
|
+
source: "PickerRecent.qml"
|
|
257
|
+
}
|
|
258
|
+
Connections {
|
|
259
|
+
target: recentReader.item
|
|
260
|
+
function onRefreshed() {
|
|
261
|
+
root.recentPaths = recentReader.item.paths
|
|
262
|
+
root.recentVisits = recentReader.item.visits
|
|
263
|
+
root.recentKept = true
|
|
264
|
+
root.recentReading = false
|
|
265
|
+
root.recentReads += 1
|
|
266
|
+
// Drop the bounded parsed model later, after the reader finishes emitting this signal.
|
|
267
|
+
Qt.callLater(function () { if (!root.recentReading) recentReader.active = false })
|
|
268
|
+
var askers = root.recentRequesters
|
|
269
|
+
root.recentRequesters = []
|
|
270
|
+
for (var i = 0; i < askers.length; i++) root.recentRequested(root.recentPaths, askers[i], root.recentVisits)
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// The context menu's gate for the two Dropbox rows, so the pane never reaches into the rail.
|
|
275
|
+
readonly property bool dropboxReady: root.service !== null && root.service.dropboxReady
|
|
276
|
+
readonly property var providerService: root.service
|
|
277
|
+
|
|
278
|
+
DeviceMounts {
|
|
279
|
+
id: devices
|
|
280
|
+
polling: root.polling
|
|
281
|
+
showUnmounted: root.placesState.showUnmounted !== false
|
|
282
|
+
onOpened: function (path) { root.opened(path) }
|
|
283
|
+
onMessage: function (text, isError) { root.message(text, isError) }
|
|
284
|
+
onOperationResult: function (headline, detail, isError) { root.operationResult(headline, detail, isError) }
|
|
285
|
+
onForgetMessage: function (text) { root.forgetMessage(text) }
|
|
286
|
+
// An eject releases the volume, so readers on it stop first and panes on it go Home.
|
|
287
|
+
onQuiesce: function (path) { if (root.navigationPane) root.navigationPane.quiesceVolume(path) }
|
|
288
|
+
onUnlockRequested: function (device, label, size, fstype) { root.unlockRequested(device, label, size, fstype) }
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Lists and unmounts only: activate() below routes a phone's mount-and-open through the same openShare leg a share rides.
|
|
292
|
+
PhoneMounts {
|
|
293
|
+
id: phones
|
|
294
|
+
listingText: root.service !== null ? root.service.mountListing : ""
|
|
295
|
+
listingAnswered: root.service !== null && root.service.listingAnswered
|
|
296
|
+
onMessage: function (text, isError) { root.message(text, isError) }
|
|
297
|
+
onReleased: if (root.service) root.service.pollMounts()
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// The mount service lives window-long in ui/WindowBody.qml's network host, injected through
|
|
301
|
+
// ui/PaneRail.qml: every call below reaches the same instance whether this rail is shown or
|
|
302
|
+
// has been unloaded mid-mount, and the answers land through ui/PaneRail.qml's own
|
|
303
|
+
// connections rather than through this rail.
|
|
304
|
+
|
|
305
|
+
// Home is in neither file, so it is prepended; the merge and its first-position-wins rule are Places.favorites'.
|
|
306
|
+
Connections {
|
|
307
|
+
target: Favourites
|
|
308
|
+
function onFailed(message) { root.message(message, true) }
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// NetworkDialog's saved() drives this reload because a watch set up before its parent directory existed never fires, and it blocks because "forget" derives its body from this text: measured here, an asynchronous reload put a removed line back.
|
|
312
|
+
function reloadBookmarks() {
|
|
313
|
+
bookmarksFile.reload()
|
|
314
|
+
bookmarksFile.waitForJob()
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function networkResult() {
|
|
318
|
+
return root.service !== null ? root.service.result : ""
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// The eject mark's one click names its release row, never rows[0], which a volume's Open would win; Ctrl+E keys its release by Mounts.railKey too.
|
|
322
|
+
function ejectRow(index) {
|
|
323
|
+
var entry = root.entries[index]
|
|
324
|
+
if (!entry)
|
|
325
|
+
return
|
|
326
|
+
var action = Eject.releaseAction(entry)
|
|
327
|
+
if (action.length === 0)
|
|
328
|
+
return
|
|
329
|
+
root.releaseChosen(action, Mounts.railKey(entry))
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// Right click is the whole affordance, and which rows offer what is ui/js/Mounts.js "rowMenu"'s: a row with nothing to offer opens no menu at all.
|
|
333
|
+
function openRailMenu(index, scenePosition) {
|
|
334
|
+
root.cancelRename()
|
|
335
|
+
var entry = root.entries[index]
|
|
336
|
+
if (!entry || !root.menu) {
|
|
337
|
+
return
|
|
338
|
+
}
|
|
339
|
+
root.cursorIndex = index
|
|
340
|
+
RailMenu.railMenuFor(root, entry, scenePosition, ViewState.menuHidden)
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// The keyboard's entrance to the same menu: ui/js/Mounts.js "raiseMenu" has already asked whether the row releases anything, so this only turns the cursor into a point.
|
|
344
|
+
function openCursorMenu() {
|
|
345
|
+
var row = root.railItemFor(root.cursorIndex)
|
|
346
|
+
if (!row)
|
|
347
|
+
return
|
|
348
|
+
root.openRailMenu(root.cursorIndex, row.mapToItem(null, Style.spacing.rowPaddingX, row.height))
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// A chosen row arrives with its key rather than its position, and RailMenu.release names the row.
|
|
352
|
+
function releaseChosen(action, key) {
|
|
353
|
+
if (key === "trash") return
|
|
354
|
+
// A place and a favourite are both a path, and ui/js/PlaceMenu.js owns what their rows do.
|
|
355
|
+
if (key.indexOf("place:") === 0 || key.indexOf("favourite:") === 0) {
|
|
356
|
+
PlaceMenu.perform(action, key, root, Favourites)
|
|
357
|
+
return
|
|
358
|
+
}
|
|
359
|
+
RailMenu.release(action, key, devices, root.service, root)
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
Connections {
|
|
363
|
+
target: root.menu
|
|
364
|
+
function onRailChosen(action, key) { root.releaseChosen(action, key) }
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// The host exists from creation, so a row pressed before the rail arrives still answers.
|
|
368
|
+
function networkHost() {
|
|
369
|
+
if (root.service) return root.service
|
|
370
|
+
if (root.navigationPane) return root.navigationPane.ensureNetworkService()
|
|
371
|
+
return null
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// The favourites store persists reorders; a refused move keeps its row and reports the failure.
|
|
375
|
+
function moveFavourite(from, to) {
|
|
376
|
+
root.reorderLine = -1
|
|
377
|
+
if (to !== from)
|
|
378
|
+
Favourites.move(from, to)
|
|
379
|
+
}
|
|
380
|
+
// A favourite's path is already real and opens directly; a share or a volume may need its Service.
|
|
381
|
+
function openFavourite(index) {
|
|
382
|
+
Places.openEntry(root.userFavouriteEntries[index], {
|
|
383
|
+
pane: root.navigationPane, opened: root.opened, message: root.message,
|
|
384
|
+
networkHost: root.networkHost, trash: root.trashRequested
|
|
385
|
+
})
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
function activate(index) {
|
|
389
|
+
root.cancelRename()
|
|
390
|
+
root.cursorIndex = index
|
|
391
|
+
var entry = root.entries[index]
|
|
392
|
+
if (!entry) return
|
|
393
|
+
if (entry.kind === "favourite") { root.openFavourite(entry.favouriteIndex); return }
|
|
394
|
+
if (entry.kind === "home") { root.opened(entry.path); return }
|
|
395
|
+
if (entry.kind === "recent") { root.readRecent(); return }
|
|
396
|
+
if (entry.kind === "trash") { root.trashRequested(); return }
|
|
397
|
+
if (entry.kind === "tag") { root.navigationPane.tags().openTag(entry.tag); return }
|
|
398
|
+
var rest = index - root.placesEntries.length
|
|
399
|
+
if (rest < root.networkEntries.length) root.service.activate(rest, root.navigationPane)
|
|
400
|
+
// A phone mounts, resolves and opens the way a share does.
|
|
401
|
+
else if (entry.kind === "phone") { var phoneHost = root.networkHost(); if (phoneHost) phoneHost.openShare(entry.uri, entry.mounted, entry.label, false, { origin: root.navigationPane }) }
|
|
402
|
+
else devices.activate(rest - root.networkEntries.length)
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// RailMenu.release hands the phone action back here, because the phone Service is this rail's own child.
|
|
406
|
+
function releasePhone(key) { phones.release(key) }
|
|
407
|
+
// Its Mount and Open rows are the row's own activation, resolved by key because the poll renumbers.
|
|
408
|
+
function openPhone(key) {
|
|
409
|
+
var e = phones.entries[Mounts.rowByKey(phones.entries, key)]
|
|
410
|
+
var host = e ? root.networkHost() : null
|
|
411
|
+
if (e && host) host.openShare(e.uri, e.mounted, e.label, false, { origin: root.navigationPane })
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// Network only: neither a favourite nor a device has a bookmark line of its own shape for
|
|
415
|
+
// Places.relabel to find, and a volume's label lives on the filesystem, not in a rail file.
|
|
416
|
+
function startRename(index) {
|
|
417
|
+
if (index < root.placesEntries.length)
|
|
418
|
+
return
|
|
419
|
+
if (index >= root.placesEntries.length + root.networkEntries.length)
|
|
420
|
+
return
|
|
421
|
+
// A kernel share row has no saved place to rename, and relabelling it would append a file:// bookmark the network rail never draws.
|
|
422
|
+
var entry = root.networkEntries[index - root.placesEntries.length]
|
|
423
|
+
if (entry && entry.editable === false)
|
|
424
|
+
return
|
|
425
|
+
root.renamingIndex = index
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// The rail's own answer to ui/Pane.qml's renameEditor: the live editor row, or null.
|
|
429
|
+
function renameEditor() {
|
|
430
|
+
if (root.renamingIndex < 0)
|
|
431
|
+
return null
|
|
432
|
+
var item = netRepeater.itemAt(root.renamingIndex - root.placesEntries.length)
|
|
433
|
+
return item && item.renaming ? item : null
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
function cancelRename() {
|
|
437
|
+
if (root.renamingIndex < 0)
|
|
438
|
+
return
|
|
439
|
+
root.renamingIndex = -1
|
|
440
|
+
root.renameFinished()
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// An empty submitted name reverts rather than writing an empty label.
|
|
444
|
+
function commitRename(index, name) {
|
|
445
|
+
if (root.renamingIndex !== index) return
|
|
446
|
+
root.renamingIndex = -1
|
|
447
|
+
root.renameFinished()
|
|
448
|
+
var trimmed = String(name || "").trim()
|
|
449
|
+
if (trimmed.length === 0)
|
|
450
|
+
return
|
|
451
|
+
var entry = root.networkEntries[index - root.placesEntries.length]
|
|
452
|
+
if (!entry)
|
|
453
|
+
return
|
|
454
|
+
root.service.rename(entry.uri, trimmed)
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// Auto-hide reveals the rail over the listing, so on glass it hides the rows under it the way a menu does.
|
|
458
|
+
Rectangle {
|
|
459
|
+
anchors.fill: parent
|
|
460
|
+
color: ViewState.railAutoHide ? Theme.color.surface : Glass.surface
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
onCursorIndexChanged: { root.markFocused = false; root.revealCursor() }
|
|
464
|
+
|
|
465
|
+
// Anchored inside the Flickable's contentItem, so a row's y is already the scroll coordinate.
|
|
466
|
+
function revealCursor() {
|
|
467
|
+
var row = root.railItemFor(root.cursorIndex)
|
|
468
|
+
if (!row)
|
|
469
|
+
return
|
|
470
|
+
var p = row.mapToItem(scroller.contentItem, 0, 0)
|
|
471
|
+
if (p.y < scroller.contentY)
|
|
472
|
+
scroller.contentY = p.y
|
|
473
|
+
else if (p.y + row.height > scroller.contentY + scroller.height)
|
|
474
|
+
scroller.contentY = p.y + row.height - scroller.height
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// The rows live in a viewport: a rail taller than its own height could show no bottom row at all.
|
|
478
|
+
Timer {
|
|
479
|
+
id: availability
|
|
480
|
+
interval: 120
|
|
481
|
+
onTriggered: {
|
|
482
|
+
var indices = []
|
|
483
|
+
for (var i = 0; i < favRepeater.count; i++) {
|
|
484
|
+
var item = favRepeater.itemAt(i)
|
|
485
|
+
var point = item ? item.mapToItem(scroller.contentItem, 0, 0) : null
|
|
486
|
+
if (point && point.y + item.height > scroller.contentY && point.y < scroller.contentY + scroller.height)
|
|
487
|
+
indices.push(i)
|
|
488
|
+
}
|
|
489
|
+
Favourites.inspect(indices)
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
Flickable {
|
|
493
|
+
id: scroller
|
|
494
|
+
onContentYChanged: { availability.restart(); fileDrop.reaim() }
|
|
495
|
+
anchors.fill: parent
|
|
496
|
+
clip: true
|
|
497
|
+
contentWidth: width
|
|
498
|
+
contentHeight: rail.height + 2 * Style.spacing.rowPaddingX
|
|
499
|
+
boundsBehavior: Flickable.StopAtBounds
|
|
500
|
+
|
|
501
|
+
FastScrollHandler {
|
|
502
|
+
parent: scroller
|
|
503
|
+
flickable: scroller
|
|
504
|
+
}
|
|
505
|
+
// No bar and no lane: rows fill the rail and still scroll by wheel, touchpad and keys.
|
|
506
|
+
Column {
|
|
507
|
+
id: rail
|
|
508
|
+
anchors.top: parent.top
|
|
509
|
+
anchors.topMargin: Style.spacing.rowPaddingX
|
|
510
|
+
anchors.left: parent.left
|
|
511
|
+
anchors.right: parent.right
|
|
512
|
+
|
|
513
|
+
RailHeading {
|
|
514
|
+
id: placesHeading
|
|
515
|
+
visible: root.homeEntries.length + root.trashEntries.length > 0
|
|
516
|
+
text: "PLACES"
|
|
517
|
+
}
|
|
518
|
+
Repeater {
|
|
519
|
+
id: homeLeadRepeater
|
|
520
|
+
model: root.homeLead
|
|
521
|
+
delegate: SidebarRow {
|
|
522
|
+
lit: index === root.litIndex
|
|
523
|
+
highlighted: index === root.highlightedIndex
|
|
524
|
+
cursor: root.cursorDrawn && index === root.cursorIndex
|
|
525
|
+
focused: root.focused
|
|
526
|
+
onActivated: function (idx) { root.activate(idx) }
|
|
527
|
+
onMenuRequested: function(idx, pos) { root.openRailMenu(idx, pos) }
|
|
528
|
+
onTabRequested: function (idx) { PlaceMenu.openTabAt(root, idx) }
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
Repeater {
|
|
532
|
+
id: recentRepeater
|
|
533
|
+
model: root.recentEntries
|
|
534
|
+
delegate: SidebarRow {
|
|
535
|
+
lit: index + root.homeLead.length === root.litIndex
|
|
536
|
+
highlighted: index + root.homeLead.length === root.highlightedIndex
|
|
537
|
+
cursor: root.cursorDrawn && index + root.homeLead.length === root.cursorIndex
|
|
538
|
+
focused: root.focused
|
|
539
|
+
onActivated: function (idx) { root.activate(idx + root.homeLead.length) }
|
|
540
|
+
onMenuRequested: function(idx, pos) { root.openRailMenu(idx + root.homeLead.length, pos) }
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
Repeater {
|
|
544
|
+
id: homeRestRepeater
|
|
545
|
+
model: root.homeRest
|
|
546
|
+
delegate: SidebarRow {
|
|
547
|
+
lit: index + root.homeLead.length + root.recentEntries.length === root.litIndex
|
|
548
|
+
highlighted: index + root.homeLead.length + root.recentEntries.length === root.highlightedIndex
|
|
549
|
+
cursor: root.cursorDrawn && index + root.homeLead.length + root.recentEntries.length === root.cursorIndex
|
|
550
|
+
focused: root.focused
|
|
551
|
+
onActivated: function (idx) { root.activate(idx + root.homeLead.length + root.recentEntries.length) }
|
|
552
|
+
onMenuRequested: function(idx, pos) { root.openRailMenu(idx + root.homeLead.length + root.recentEntries.length, pos) }
|
|
553
|
+
onTabRequested: function (idx) { PlaceMenu.openTabAt(root, idx + root.homeLead.length + root.recentEntries.length) }
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
Repeater {
|
|
557
|
+
id: trashRepeater
|
|
558
|
+
model: root.trashEntries
|
|
559
|
+
delegate: RailTrashRow { rail: root }
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
RailHeading {
|
|
563
|
+
id: favouritesHeading
|
|
564
|
+
visible: root.userFavouriteEntries.length > 0
|
|
565
|
+
text: "FAVORITES"
|
|
566
|
+
topExtra: placesHeading.visible ? Style.spacing.panelGap : 0
|
|
567
|
+
}
|
|
568
|
+
Repeater {
|
|
569
|
+
id: favRepeater
|
|
570
|
+
model: root.userFavouriteEntries
|
|
571
|
+
delegate: SidebarRow {
|
|
572
|
+
lit: index + root.homeLead.length + root.recentEntries.length + root.homeRest.length + root.trashEntries.length === root.litIndex
|
|
573
|
+
highlighted: index + root.homeLead.length + root.recentEntries.length + root.homeRest.length + root.trashEntries.length === root.highlightedIndex
|
|
574
|
+
cursor: root.cursorDrawn && index + root.homeLead.length + root.recentEntries.length + root.homeRest.length + root.trashEntries.length === root.cursorIndex
|
|
575
|
+
focused: root.focused
|
|
576
|
+
// The rail's own reorder drag, persisted through the favourites store.
|
|
577
|
+
dragFrom: modelData.favouriteIndex
|
|
578
|
+
lineCount: root.userFavouriteEntries.length
|
|
579
|
+
onMoved: function (to) { root.moveFavourite(dragFrom, to) }
|
|
580
|
+
onReorderAt: function (line) { root.reorderLine = line }
|
|
581
|
+
onActivated: function (idx) { root.activate(idx + root.homeLead.length + root.recentEntries.length + root.homeRest.length + root.trashEntries.length) }
|
|
582
|
+
onMenuRequested: function (idx, pos) { root.openRailMenu(idx + root.homeLead.length + root.recentEntries.length + root.homeRest.length + root.trashEntries.length, pos) }
|
|
583
|
+
onTabRequested: function (idx) { PlaceMenu.openTabAt(root, idx + root.homeLead.length + root.recentEntries.length + root.homeRest.length + root.trashEntries.length) }
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
// The OEM panel idiom's own group gap, not the tighter row-to-row rhythm rows keep inside a group.
|
|
588
|
+
Item {
|
|
589
|
+
id: netGap
|
|
590
|
+
// The TAGS section lives inside this gap, so its rows end the places group by construction.
|
|
591
|
+
visible: root.networkEntries.length > 0 || (root.tagSection !== null && root.placesState.showTags === true)
|
|
592
|
+
width: rail.width
|
|
593
|
+
height: ((root.tagSection !== null && root.placesState.showTags === true) ? root.tagSection.height : 0) + (root.networkEntries.length > 0 ? Style.spacing.panelGap : 0)
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
// Self-hides with its list below when gio, the bookmarks file and Dropbox all have nothing to say.
|
|
597
|
+
Item {
|
|
598
|
+
visible: root.networkEntries.length > 0
|
|
599
|
+
width: rail.width
|
|
600
|
+
height: netHeading.implicitHeight + Style.spacing.rowGap
|
|
601
|
+
|
|
602
|
+
RailHeading {
|
|
603
|
+
id: netHeading
|
|
604
|
+
noBottom: true
|
|
605
|
+
text: "NETWORK"
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// A hand-drawn plus, not a Text "+": at caption size the font glyph read as a Christian cross, not a plus. Sized off the heading's own font token.
|
|
609
|
+
Glyph {
|
|
610
|
+
id: addGlyph
|
|
611
|
+
// The rail's trailing indicator slot: caption wide, inset by rowPaddingX, anchored exactly as ui/SidebarRow.qml's dot is.
|
|
612
|
+
anchors.right: parent.right
|
|
613
|
+
anchors.rightMargin: Style.spacing.rowPaddingX
|
|
614
|
+
anchors.verticalCenter: netHeading.verticalCenter
|
|
615
|
+
name: "plus"
|
|
616
|
+
color: Theme.color.mutedFrame
|
|
617
|
+
width: Theme.font.caption
|
|
618
|
+
height: width
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
// Bigger than the ink it covers, so it centres on the ink's own box, in real pixels: a centre anchor quantises an odd size difference and leaves the two centres half a pixel apart.
|
|
622
|
+
Item {
|
|
623
|
+
id: addMark
|
|
624
|
+
width: Math.max(Theme.hitMin, Theme.font.caption)
|
|
625
|
+
height: width
|
|
626
|
+
x: addGlyph.x + (addGlyph.width - width) / 2
|
|
627
|
+
y: addGlyph.y + (addGlyph.height - height) / 2
|
|
628
|
+
Accessible.role: Accessible.Button
|
|
629
|
+
Accessible.name: "Add network location"
|
|
630
|
+
Accessible.onPressAction: root.addRequested()
|
|
631
|
+
TapHandler { onTapped: root.addRequested() }
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
Repeater {
|
|
636
|
+
id: netRepeater
|
|
637
|
+
model: root.networkEntries
|
|
638
|
+
delegate: SidebarRow {
|
|
639
|
+
lit: index + root.placesEntries.length === root.litIndex
|
|
640
|
+
highlighted: index + root.placesEntries.length === root.highlightedIndex
|
|
641
|
+
cursor: root.cursorDrawn && index + root.placesEntries.length === root.cursorIndex
|
|
642
|
+
markFocused: root.markFocused && cursor
|
|
643
|
+
focused: root.focused
|
|
644
|
+
renaming: (index + root.placesEntries.length) === root.renamingIndex
|
|
645
|
+
onActivated: function (idx) { root.activate(idx + root.placesEntries.length) }
|
|
646
|
+
onEjectRequested: function (idx) { root.ejectRow(idx + root.placesEntries.length) }
|
|
647
|
+
onMenuRequested: function (idx, pos) { root.openRailMenu(idx + root.placesEntries.length, pos) }
|
|
648
|
+
onRenameCommitted: function (idx, text) { root.commitRename(idx + root.placesEntries.length, text) }
|
|
649
|
+
onRenameCancelled: root.cancelRename()
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
Item {
|
|
654
|
+
visible: root.deviceEntries.length > 0
|
|
655
|
+
width: rail.width
|
|
656
|
+
height: Style.spacing.panelGap
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
// Self-hides with its list where lsblk reports no disk and no drive was found by looking, and carries no add mark: nothing here is bookmarked.
|
|
660
|
+
RailHeading {
|
|
661
|
+
id: devHeading
|
|
662
|
+
visible: root.deviceEntries.length > 0
|
|
663
|
+
text: "DEVICES"
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
Repeater {
|
|
667
|
+
id: devRepeater
|
|
668
|
+
model: root.deviceEntries
|
|
669
|
+
delegate: SidebarRow {
|
|
670
|
+
lit: index + root.placesEntries.length + root.networkEntries.length === root.litIndex
|
|
671
|
+
highlighted: index + root.placesEntries.length + root.networkEntries.length === root.highlightedIndex
|
|
672
|
+
cursor: root.cursorDrawn && index + root.placesEntries.length + root.networkEntries.length === root.cursorIndex
|
|
673
|
+
markFocused: root.markFocused && cursor
|
|
674
|
+
focused: root.focused
|
|
675
|
+
onActivated: function (idx) { root.activate(idx + root.placesEntries.length + root.networkEntries.length) }
|
|
676
|
+
onEjectRequested: function (idx) { root.ejectRow(idx + root.placesEntries.length + root.networkEntries.length) }
|
|
677
|
+
onMenuRequested: function (idx, pos) { root.openRailMenu(idx + root.placesEntries.length + root.networkEntries.length, pos) }
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
// Sidebar040 specimen 1: the bar lies over the boundary, one hairline in the row above and the rest under it.
|
|
682
|
+
Rectangle {
|
|
683
|
+
readonly property var row: favRepeater.itemAt(Math.min(root.reorderLine, favRepeater.count - 1))
|
|
684
|
+
readonly property real boundary: row ? row.y + (root.reorderLine === favRepeater.count ? row.height : 0) : 0
|
|
685
|
+
visible: root.reorderLine >= 0 && root.reorderLine <= favRepeater.count && row !== null
|
|
686
|
+
width: rail.width
|
|
687
|
+
height: Theme.accentEdge * Theme.spacing.hairline
|
|
688
|
+
y: boundary - Theme.spacing.hairline + rail.y
|
|
689
|
+
color: Theme.color.accent
|
|
690
|
+
z: 1
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
// The "+" ink, its hit target and the rail's own indicator dot: the three boxes that share one centre.
|
|
695
|
+
function networkMarkItems() { var netRow = netRepeater.itemAt(0); return [addGlyph, addMark, netRow ? netRow.indicatorSlot : null] }
|
|
696
|
+
function headingItems() { return [placesHeading, favouritesHeading, netHeading, devHeading] }
|
|
697
|
+
// The rail has no ListView virtualization, so every row already exists; the same itemFor idiom ui/Pane.qml uses for the list, so a test can find a rail row's on-screen box.
|
|
698
|
+
function railItemFor(index) {
|
|
699
|
+
if (index < root.homeLead.length) return homeLeadRepeater.itemAt(index)
|
|
700
|
+
var rest = index - root.homeLead.length
|
|
701
|
+
if (rest < root.recentEntries.length) return recentRepeater.itemAt(rest)
|
|
702
|
+
rest -= root.recentEntries.length
|
|
703
|
+
if (rest < root.homeRest.length) return homeRestRepeater.itemAt(rest)
|
|
704
|
+
rest -= root.homeRest.length
|
|
705
|
+
if (rest < root.trashEntries.length) return trashRepeater.itemAt(rest)
|
|
706
|
+
rest -= root.trashEntries.length
|
|
707
|
+
if (rest < root.userFavouriteEntries.length) return favRepeater.itemAt(rest)
|
|
708
|
+
rest -= root.userFavouriteEntries.length
|
|
709
|
+
if (rest < root.tagRows.length) return root.tagSection.itemAt(rest)
|
|
710
|
+
rest -= root.tagRows.length
|
|
711
|
+
if (rest < root.networkEntries.length)
|
|
712
|
+
return netRepeater.itemAt(rest)
|
|
713
|
+
rest -= root.networkEntries.length
|
|
714
|
+
return devRepeater.itemAt(rest)
|
|
715
|
+
}
|
|
716
|
+
// Above the Flickable and every row, because a PointHandler under their exclusive press grab is never given the press; a passive handler leaves the press to the row.
|
|
717
|
+
Item {
|
|
718
|
+
anchors.fill: parent
|
|
719
|
+
z: 1
|
|
720
|
+
PointHandler {
|
|
721
|
+
acceptedButtons: Qt.AllButtons
|
|
722
|
+
// After pressed(), which can hand an overlay rail the keyboard, so the press that claimed it still hides the frame.
|
|
723
|
+
onActiveChanged: if (active) { root.pressed(); if (root.focused) root.pointerFocus = true }
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
// The rail edge, one Divider shared with the column edges.
|
|
727
|
+
Flea.Divider {
|
|
728
|
+
anchors.right: parent.right
|
|
729
|
+
anchors.top: parent.top
|
|
730
|
+
anchors.bottom: parent.bottom
|
|
731
|
+
}
|
|
732
|
+
}
|