mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-05-02 02:22:06 -04:00
Compare commits
7 Commits
e9fa2c78ee
...
8e047f45f5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8e047f45f5 | ||
|
|
fbe8cbb23f | ||
|
|
28315a165f | ||
|
|
1b32829dac | ||
|
|
1fce29324f | ||
|
|
1fab90178a | ||
|
|
eb04ab7dca |
@@ -1490,6 +1490,19 @@ func checkGreeterStatus() error {
|
||||
}
|
||||
if stat, err := os.Stat(cacheDir); err == nil && stat.IsDir() {
|
||||
fmt.Printf(" ✓ %s exists\n", cacheDir)
|
||||
requiredSubdirs := []string{".local/state", ".local/share", ".cache"}
|
||||
missingSubdirs := false
|
||||
for _, sub := range requiredSubdirs {
|
||||
subPath := filepath.Join(cacheDir, sub)
|
||||
if _, err := os.Stat(subPath); os.IsNotExist(err) {
|
||||
fmt.Printf(" ⚠ Missing required subdir: %s\n", subPath)
|
||||
missingSubdirs = true
|
||||
}
|
||||
}
|
||||
if missingSubdirs {
|
||||
fmt.Println(" Run 'dms greeter sync' to initialize the cache directory structure.")
|
||||
allGood = false
|
||||
}
|
||||
} else {
|
||||
fmt.Printf(" ✗ %s not found\n", cacheDir)
|
||||
fmt.Printf(" %s\n", packageInstallHint())
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/deps"
|
||||
@@ -113,6 +112,17 @@ func containsString(values []string, target string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func debianRepoArchitecture(arch string) string {
|
||||
switch arch {
|
||||
case "amd64", "x86_64":
|
||||
return "amd64"
|
||||
case "arm64", "aarch64":
|
||||
return "arm64"
|
||||
default:
|
||||
return arch
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebianDistribution) GetPackageMapping(wm deps.WindowManager) map[string]PackageMapping {
|
||||
return d.GetPackageMappingWithVariants(wm, make(map[string]deps.PackageVariant))
|
||||
}
|
||||
@@ -460,7 +470,7 @@ func (d *DebianDistribution) enableOBSRepos(ctx context.Context, obsPkgs []Packa
|
||||
}
|
||||
|
||||
// Add repository
|
||||
repoLine := fmt.Sprintf("deb [signed-by=%s arch=%s] %s/ /", keyringPath, runtime.GOARCH, baseURL)
|
||||
repoLine := fmt.Sprintf("deb [signed-by=%s arch=%s] %s/ /", keyringPath, debianRepoArchitecture(osInfo.Architecture), baseURL)
|
||||
|
||||
progressChan <- InstallProgressMsg{
|
||||
Phase: PhaseSystemPackages,
|
||||
|
||||
@@ -9,7 +9,7 @@ Vcs-Browser: https://github.com/AvengeMedia/DankMaterialShell
|
||||
Vcs-Git: https://github.com/AvengeMedia/DankMaterialShell.git
|
||||
|
||||
Package: dms
|
||||
Architecture: amd64
|
||||
Architecture: amd64 arm64
|
||||
Depends: ${misc:Depends},
|
||||
quickshell | quickshell-git,
|
||||
accountsservice,
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
dms-distropkg-amd64.gz
|
||||
dms-distropkg-arm64.gz
|
||||
dms-source.tar.gz
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# Include files that are normally excluded by .gitignore
|
||||
# These are needed for the build process on Launchpad
|
||||
tar-ignore = !dms-distropkg-amd64.gz
|
||||
tar-ignore = !dms-distropkg-arm64.gz
|
||||
tar-ignore = !dms-source.tar.gz
|
||||
|
||||
@@ -7,7 +7,6 @@ import qs.Modals.Clipboard
|
||||
import qs.Modals.Greeter
|
||||
import qs.Modals.Settings
|
||||
import qs.Modals.DankLauncherV2
|
||||
import qs.Modals
|
||||
import qs.Modules
|
||||
import qs.Modules.AppDrawer
|
||||
import qs.Modules.DankDash
|
||||
@@ -820,9 +819,8 @@ Item {
|
||||
|
||||
content: Component {
|
||||
Notepad {
|
||||
onHideRequested: {
|
||||
notepadSlideout.hide();
|
||||
}
|
||||
slideout: notepadSlideout
|
||||
onHideRequested: notepadSlideout.hide()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import QtQuick
|
||||
import QtQuick.Effects
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Hyprland
|
||||
@@ -17,7 +16,6 @@ Item {
|
||||
property var spotlightContent: launcherContentLoader.item
|
||||
property bool openedFromOverview: false
|
||||
property bool isClosing: false
|
||||
property bool _windowEnabled: true
|
||||
property bool _pendingInitialize: false
|
||||
property string _pendingQuery: ""
|
||||
property string _pendingMode: ""
|
||||
@@ -267,38 +265,26 @@ Item {
|
||||
if (Quickshell.screens.length === 0)
|
||||
return;
|
||||
|
||||
const screen = launcherWindow.screen;
|
||||
const screenName = screen?.name;
|
||||
|
||||
let needsReset = !screen || !screenName;
|
||||
if (!needsReset) {
|
||||
needsReset = true;
|
||||
const screenName = launcherWindow.screen?.name;
|
||||
if (screenName) {
|
||||
for (let i = 0; i < Quickshell.screens.length; i++) {
|
||||
if (Quickshell.screens[i].name === screenName) {
|
||||
needsReset = false;
|
||||
break;
|
||||
}
|
||||
if (Quickshell.screens[i].name === screenName)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!needsReset)
|
||||
return;
|
||||
if (spotlightOpen)
|
||||
hide();
|
||||
|
||||
const newScreen = CompositorService.getFocusedScreen() ?? Quickshell.screens[0];
|
||||
if (!newScreen)
|
||||
return;
|
||||
|
||||
root._windowEnabled = false;
|
||||
launcherWindow.screen = newScreen;
|
||||
Qt.callLater(() => {
|
||||
root._windowEnabled = true;
|
||||
});
|
||||
if (newScreen)
|
||||
launcherWindow.screen = newScreen;
|
||||
}
|
||||
}
|
||||
|
||||
PanelWindow {
|
||||
id: launcherWindow
|
||||
visible: root._windowEnabled && (spotlightOpen || isClosing)
|
||||
visible: spotlightOpen || isClosing
|
||||
color: "transparent"
|
||||
exclusionMode: ExclusionMode.Ignore
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@ Singleton {
|
||||
property bool nightModeEnabled: false
|
||||
|
||||
Component.onCompleted: {
|
||||
Quickshell.execDetached(["mkdir", "-p", greetCfgDir]);
|
||||
loadMemory();
|
||||
loadSessionConfig();
|
||||
}
|
||||
|
||||
@@ -87,8 +87,7 @@ exec_compositor() {
|
||||
exec "$@" > >(systemd-cat -t "dms-greeter/$log_tag" -p info) 2>&1
|
||||
fi
|
||||
|
||||
local log_file="$CACHE_DIR/$log_tag.log"
|
||||
exec "$@" >> "$log_file" 2>&1
|
||||
exec "$@"
|
||||
}
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
@@ -180,19 +179,10 @@ export QT_WAYLAND_DISABLE_WINDOWDECORATION=1
|
||||
export EGL_PLATFORM=gbm
|
||||
export DMS_RUN_GREETER=1
|
||||
|
||||
ensure_cache_tree() {
|
||||
local base="$1"
|
||||
mkdir -p "$base/.local/state" "$base/.local/share" "$base/.cache"
|
||||
}
|
||||
|
||||
if ! ensure_cache_tree "$CACHE_DIR" 2>/dev/null; then
|
||||
FALLBACK_CACHE_DIR="/tmp/dms-greeter-${UID:-$(id -u)}"
|
||||
echo "Warning: cache directory '$CACHE_DIR' is not writable; falling back to '$FALLBACK_CACHE_DIR'" >&2
|
||||
CACHE_DIR="$FALLBACK_CACHE_DIR"
|
||||
if ! ensure_cache_tree "$CACHE_DIR"; then
|
||||
echo "Error: failed to initialize fallback cache directory '$CACHE_DIR'" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ ! -d "$CACHE_DIR" ]]; then
|
||||
echo "Error: cache directory '$CACHE_DIR' does not exist." >&2
|
||||
echo " Run 'dms greeter sync' to initialize it, or pass --cache-dir to an existing directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
export DMS_GREET_CFG_DIR="$CACHE_DIR"
|
||||
|
||||
@@ -21,6 +21,7 @@ Item {
|
||||
property var currentTab: NotepadStorageService.tabs.length > NotepadStorageService.currentTabIndex ? NotepadStorageService.tabs[NotepadStorageService.currentTabIndex] : null
|
||||
property bool showSettingsMenu: false
|
||||
property string pendingSaveContent: ""
|
||||
property var slideout: null
|
||||
|
||||
signal hideRequested
|
||||
signal previewRequested(string content)
|
||||
@@ -29,6 +30,14 @@ Item {
|
||||
service: NotepadStorageService
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: slideout
|
||||
enabled: slideout !== null
|
||||
function onAboutToHide() {
|
||||
textEditor.autoSaveToSession()
|
||||
}
|
||||
}
|
||||
|
||||
function hasUnsavedChanges() {
|
||||
return textEditor.hasUnsavedChanges();
|
||||
}
|
||||
@@ -204,7 +213,8 @@ Item {
|
||||
}
|
||||
|
||||
onEscapePressed: {
|
||||
root.hideRequested();
|
||||
textEditor.autoSaveToSession()
|
||||
root.hideRequested()
|
||||
}
|
||||
|
||||
onSettingsRequested: {
|
||||
|
||||
@@ -10,6 +10,10 @@ Column {
|
||||
|
||||
property var currentTab: NotepadStorageService.tabs.length > NotepadStorageService.currentTabIndex ? NotepadStorageService.tabs[NotepadStorageService.currentTabIndex] : null
|
||||
property bool contentLoaded: false
|
||||
property int draggedIndex: -1
|
||||
property int dropTargetIndex: -1
|
||||
property bool suppressShiftAnimation: false
|
||||
readonly property real tabItemSize: 128 + Theme.spacingXS
|
||||
|
||||
signal tabSwitched(int tabIndex)
|
||||
signal tabClosed(int tabIndex)
|
||||
@@ -46,92 +50,221 @@ Column {
|
||||
Repeater {
|
||||
model: NotepadStorageService.tabs
|
||||
|
||||
delegate: Rectangle {
|
||||
delegate: Item {
|
||||
id: delegateItem
|
||||
required property int index
|
||||
required property var modelData
|
||||
|
||||
readonly property bool isActive: NotepadStorageService.currentTabIndex === index
|
||||
readonly property bool isHovered: tabMouseArea.containsMouse && !closeMouseArea.containsMouse
|
||||
readonly property real tabWidth: 128
|
||||
property bool longPressing: false
|
||||
property bool dragging: false
|
||||
property point dragStartPos: Qt.point(0, 0)
|
||||
property int targetIndex: -1
|
||||
property int originalIndex: -1
|
||||
property real dragAxisOffset: 0
|
||||
|
||||
Timer {
|
||||
id: longPressTimer
|
||||
interval: 200
|
||||
repeat: false
|
||||
onTriggered: {
|
||||
if (NotepadStorageService.tabs.length > 1) {
|
||||
delegateItem.longPressing = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
readonly property real shiftOffset: {
|
||||
if (root.draggedIndex < 0)
|
||||
return 0
|
||||
if (index === root.draggedIndex)
|
||||
return 0
|
||||
var dragIdx = root.draggedIndex
|
||||
var dropIdx = root.dropTargetIndex
|
||||
var myIdx = index
|
||||
var shiftAmount = root.tabItemSize
|
||||
if (dropIdx < 0)
|
||||
return 0
|
||||
if (dragIdx < dropIdx && myIdx > dragIdx && myIdx <= dropIdx)
|
||||
return -shiftAmount
|
||||
if (dragIdx > dropIdx && myIdx >= dropIdx && myIdx < dragIdx)
|
||||
return shiftAmount
|
||||
return 0
|
||||
}
|
||||
|
||||
width: tabWidth
|
||||
height: 32
|
||||
radius: Theme.cornerRadius
|
||||
color: isActive ? Theme.primaryPressed : isHovered ? Theme.primaryHoverLight : Theme.withAlpha(Theme.primaryPressed, 0)
|
||||
border.width: isActive ? 0 : 1
|
||||
border.color: Theme.outlineMedium
|
||||
clip: true
|
||||
z: dragging ? 100 : 0
|
||||
|
||||
transform: Translate {
|
||||
x: shiftOffset
|
||||
Behavior on x {
|
||||
enabled: !root.suppressShiftAnimation
|
||||
NumberAnimation {
|
||||
duration: 150
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: tabVisual
|
||||
anchors.fill: parent
|
||||
z: 1
|
||||
layer.enabled: dragging
|
||||
layer.smooth: true
|
||||
|
||||
transform: Translate {
|
||||
x: dragging ? dragAxisOffset : 0
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: tabRect
|
||||
anchors.fill: parent
|
||||
radius: Theme.cornerRadius
|
||||
color: isActive ? Theme.primaryPressed : isHovered ? Theme.primaryHoverLight : Theme.withAlpha(Theme.primaryPressed, 0)
|
||||
border.width: isActive || dragging ? 0 : 1
|
||||
border.color: dragging ? Theme.primary : Theme.outlineMedium
|
||||
clip: true
|
||||
|
||||
Row {
|
||||
id: tabContent
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.rightMargin: Theme.spacingM
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
id: tabText
|
||||
width: parent.width - (tabCloseButton.visible ? tabCloseButton.width + Theme.spacingXS : 0)
|
||||
text: {
|
||||
var prefix = ""
|
||||
if (hasUnsavedChangesForTab(modelData)) {
|
||||
prefix = "● "
|
||||
}
|
||||
return prefix + (modelData.title || "Untitled")
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: isActive ? Theme.primary : Theme.surfaceText
|
||||
font.weight: isActive ? Font.Medium : Font.Normal
|
||||
elide: Text.ElideMiddle
|
||||
maximumLineCount: 1
|
||||
wrapMode: Text.NoWrap
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: tabCloseButton
|
||||
width: 20
|
||||
height: 20
|
||||
radius: Theme.cornerRadius
|
||||
color: closeMouseArea.containsMouse ? Theme.surfaceTextHover : Theme.withAlpha(Theme.surfaceTextHover, 0)
|
||||
visible: NotepadStorageService.tabs.length > 1
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
DankIcon {
|
||||
name: "close"
|
||||
size: 14
|
||||
color: Theme.surfaceTextMedium
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: closeMouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
z: 100
|
||||
|
||||
onClicked: root.tabClosed(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: tabMouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
preventStealing: dragging || longPressing
|
||||
cursorShape: dragging || longPressing ? Qt.ClosedHandCursor : Qt.PointingHandCursor
|
||||
acceptedButtons: Qt.LeftButton
|
||||
|
||||
onClicked: root.tabSwitched(index)
|
||||
}
|
||||
|
||||
Row {
|
||||
id: tabContent
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.rightMargin: Theme.spacingM
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
id: tabText
|
||||
width: parent.width - (tabCloseButton.visible ? tabCloseButton.width + Theme.spacingXS : 0)
|
||||
text: {
|
||||
var prefix = "";
|
||||
if (hasUnsavedChangesForTab(modelData)) {
|
||||
prefix = "● ";
|
||||
}
|
||||
return prefix + (modelData.title || "Untitled");
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: isActive ? Theme.primary : Theme.surfaceText
|
||||
font.weight: isActive ? Font.Medium : Font.Normal
|
||||
elide: Text.ElideMiddle
|
||||
maximumLineCount: 1
|
||||
wrapMode: Text.NoWrap
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: tabCloseButton
|
||||
width: 20
|
||||
height: 20
|
||||
radius: Theme.cornerRadius
|
||||
color: closeMouseArea.containsMouse ? Theme.surfaceTextHover : Theme.withAlpha(Theme.surfaceTextHover, 0)
|
||||
visible: NotepadStorageService.tabs.length > 1
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
DankIcon {
|
||||
name: "close"
|
||||
size: 14
|
||||
color: Theme.surfaceTextMedium
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: closeMouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
z: 100
|
||||
|
||||
onClicked: {
|
||||
root.tabClosed(index);
|
||||
}
|
||||
onPressed: mouse => {
|
||||
if (mouse.button === Qt.LeftButton && NotepadStorageService.tabs.length > 1) {
|
||||
delegateItem.dragStartPos = Qt.point(mouse.x, mouse.y)
|
||||
longPressTimer.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
onReleased: mouse => {
|
||||
longPressTimer.stop()
|
||||
var wasDragging = delegateItem.dragging
|
||||
var didReorder = wasDragging && delegateItem.targetIndex >= 0 && delegateItem.targetIndex !== delegateItem.originalIndex
|
||||
|
||||
if (didReorder) {
|
||||
root.suppressShiftAnimation = true
|
||||
NotepadStorageService.reorderTab(delegateItem.originalIndex, delegateItem.targetIndex)
|
||||
}
|
||||
|
||||
delegateItem.longPressing = false
|
||||
delegateItem.dragging = false
|
||||
delegateItem.dragAxisOffset = 0
|
||||
delegateItem.targetIndex = -1
|
||||
delegateItem.originalIndex = -1
|
||||
root.draggedIndex = -1
|
||||
root.dropTargetIndex = -1
|
||||
if (didReorder) {
|
||||
Qt.callLater(() => {
|
||||
root.suppressShiftAnimation = false
|
||||
})
|
||||
}
|
||||
|
||||
if (wasDragging || mouse.button !== Qt.LeftButton)
|
||||
return
|
||||
root.tabSwitched(index)
|
||||
}
|
||||
|
||||
onPositionChanged: mouse => {
|
||||
if (delegateItem.longPressing && !delegateItem.dragging) {
|
||||
var distance = Math.sqrt(Math.pow(mouse.x - delegateItem.dragStartPos.x, 2) + Math.pow(mouse.y - delegateItem.dragStartPos.y, 2))
|
||||
if (distance > 5) {
|
||||
delegateItem.dragging = true
|
||||
delegateItem.targetIndex = index
|
||||
delegateItem.originalIndex = index
|
||||
root.draggedIndex = index
|
||||
root.dropTargetIndex = index
|
||||
}
|
||||
}
|
||||
|
||||
if (!delegateItem.dragging)
|
||||
return
|
||||
|
||||
var axisOffset = mouse.x - delegateItem.dragStartPos.x
|
||||
delegateItem.dragAxisOffset = axisOffset
|
||||
|
||||
var itemSize = root.tabItemSize
|
||||
var rawSlot = axisOffset / itemSize
|
||||
var slotOffset = rawSlot >= 0
|
||||
? Math.floor(rawSlot + 0.4)
|
||||
: Math.ceil(rawSlot - 0.4)
|
||||
var tabCount = NotepadStorageService.tabs.length
|
||||
var newTargetIndex = Math.max(0, Math.min(tabCount - 1, delegateItem.originalIndex + slotOffset))
|
||||
|
||||
if (newTargetIndex !== delegateItem.targetIndex) {
|
||||
delegateItem.targetIndex = newTargetIndex
|
||||
root.dropTargetIndex = newTargetIndex
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ Column {
|
||||
property string previewMode: "split" // split | full
|
||||
property string pluginHighlightedHtml: ""
|
||||
property string lastPluginContent: ""
|
||||
property int loadRequestId: 0
|
||||
|
||||
signal saveRequested()
|
||||
signal openRequested()
|
||||
@@ -54,10 +55,18 @@ Column {
|
||||
function loadCurrentTabContent() {
|
||||
if (!currentTab) return
|
||||
|
||||
const requestedTabId = currentTab.id
|
||||
const requestId = ++loadRequestId
|
||||
contentLoaded = false
|
||||
NotepadStorageService.loadTabContent(
|
||||
NotepadStorageService.currentTabIndex,
|
||||
(content) => {
|
||||
const activeTab = NotepadStorageService.tabs.length > NotepadStorageService.currentTabIndex
|
||||
? NotepadStorageService.tabs[NotepadStorageService.currentTabIndex]
|
||||
: null
|
||||
if (requestId !== loadRequestId || !activeTab || activeTab.id !== requestedTabId)
|
||||
return
|
||||
|
||||
lastSavedContent = content
|
||||
textArea.text = content
|
||||
contentLoaded = true
|
||||
@@ -555,7 +564,9 @@ Column {
|
||||
})
|
||||
}
|
||||
function onTabsChanged() {
|
||||
if (NotepadStorageService.tabs.length > 0 && !contentLoaded) {/* Lines 444-445 omitted */}
|
||||
if (NotepadStorageService.tabs.length > 0 && !contentLoaded) {
|
||||
loadCurrentTabContent()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -102,6 +102,14 @@ Singleton {
|
||||
metadataFile.setText(JSON.stringify(metadata, null, 2))
|
||||
}
|
||||
|
||||
function getTabById(tabId) {
|
||||
for (var i = 0; i < tabs.length; i++) {
|
||||
if (tabs[i].id === tabId)
|
||||
return tabs[i]
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
function loadTabContent(tabIndex, callback) {
|
||||
if (tabIndex < 0 || tabIndex >= tabs.length) {
|
||||
callback("")
|
||||
@@ -109,6 +117,7 @@ Singleton {
|
||||
}
|
||||
|
||||
var tab = tabs[tabIndex]
|
||||
var requestTabId = tab.id
|
||||
var fullPath = tab.isTemporary
|
||||
? baseDir + "/" + tab.filePath
|
||||
: tab.filePath
|
||||
@@ -123,6 +132,16 @@ Singleton {
|
||||
var fileChecker = fileExistsComponent.createObject(root, {
|
||||
path: fullPath,
|
||||
callback: (exists) => {
|
||||
var currentTab = root.getTabById(requestTabId)
|
||||
var currentPath = currentTab
|
||||
? (currentTab.isTemporary ? baseDir + "/" + currentTab.filePath : currentTab.filePath)
|
||||
: ""
|
||||
|
||||
if (!currentTab || currentPath !== fullPath) {
|
||||
callback("")
|
||||
return
|
||||
}
|
||||
|
||||
if (exists) {
|
||||
var loader = tabFileLoaderComponent.createObject(root, {
|
||||
path: fullPath,
|
||||
@@ -241,6 +260,28 @@ Singleton {
|
||||
saveMetadata()
|
||||
}
|
||||
|
||||
function reorderTab(fromIndex, toIndex) {
|
||||
if (fromIndex < 0 || fromIndex >= tabs.length || toIndex < 0 || toIndex >= tabs.length)
|
||||
return
|
||||
if (fromIndex === toIndex)
|
||||
return
|
||||
|
||||
var newTabs = tabs.slice()
|
||||
var moved = newTabs.splice(fromIndex, 1)[0]
|
||||
newTabs.splice(toIndex, 0, moved)
|
||||
tabs = newTabs
|
||||
|
||||
if (currentTabIndex === fromIndex) {
|
||||
currentTabIndex = toIndex
|
||||
} else if (fromIndex < currentTabIndex && toIndex >= currentTabIndex) {
|
||||
currentTabIndex--
|
||||
} else if (fromIndex > currentTabIndex && toIndex <= currentTabIndex) {
|
||||
currentTabIndex++
|
||||
}
|
||||
|
||||
saveMetadata()
|
||||
}
|
||||
|
||||
function saveTabAs(tabIndex, userPath) {
|
||||
if (tabIndex < 0 || tabIndex >= tabs.length) return
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ PanelWindow {
|
||||
property string title: ""
|
||||
property alias container: contentContainer
|
||||
property real customTransparency: -1
|
||||
signal aboutToHide
|
||||
|
||||
function show() {
|
||||
visible = true
|
||||
@@ -32,6 +33,7 @@ PanelWindow {
|
||||
}
|
||||
|
||||
function hide() {
|
||||
aboutToHide()
|
||||
isVisible = false
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user