Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
xcuserdata/
xcuserdata/
build/
.DS_Store
project.pbxproj
*.storyboard
9 changes: 6 additions & 3 deletions FlowVision.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -644,9 +644,10 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
CODE_SIGN_ENTITLEMENTS = FlowVision/FlowVision.entitlements;
CODE_SIGN_STYLE = Automatic;
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 20260111;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = FlowVision/Info.plist;
Expand All @@ -665,6 +666,7 @@
MERGED_BINARY_TYPE = automatic;
PRODUCT_BUNDLE_IDENTIFIER = netdcy.FlowVisionDbg;
PRODUCT_NAME = "$(TARGET_NAME)Dbg";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
};
Expand All @@ -677,10 +679,10 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
CODE_SIGN_ENTITLEMENTS = FlowVision/FlowVision.entitlements;
CODE_SIGN_STYLE = Automatic;
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 20260111;
DEVELOPMENT_TEAM = M9PR3WG2FN;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = FlowVision/Info.plist;
Expand All @@ -699,6 +701,7 @@
MERGED_BINARY_TYPE = automatic;
PRODUCT_BUNDLE_IDENTIFIER = netdcy.FlowVision;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
};
Expand Down
18 changes: 9 additions & 9 deletions FlowVision/Resources/Base.lproj/Main.storyboard
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="23504" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="24506" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="23504"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="24506"/>
<capability name="Named colors" minToolsVersion="9.0"/>
<capability name="System colors introduced in macOS 10.14" minToolsVersion="10.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
Expand Down Expand Up @@ -1033,7 +1033,7 @@ Gw
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="t2d-Ol-iJC"/>
</imageView>
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="0HQ-rx-KfT">
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="0HQ-rx-KfT">
<rect key="frame" x="23" y="-24" width="234" height="24"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" id="XDl-gN-nwq">
Expand Down Expand Up @@ -1170,24 +1170,24 @@ Gw
<rect key="frame" x="20" y="20" width="760" height="522"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<clipView key="contentView" drawsBackground="NO" id="A09-8j-haI">
<rect key="frame" x="0.0" y="0.0" width="745" height="522"/>
<rect key="frame" x="0.0" y="0.0" width="760" height="522"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textView wantsLayer="YES" importsGraphics="NO" richText="NO" verticallyResizable="YES" findStyle="bar" spellingCorrection="YES" smartInsertDelete="YES" id="Hvc-43-Pyw">
<rect key="frame" x="0.0" y="0.0" width="745" height="522"/>
<rect key="frame" x="0.0" y="0.0" width="760" height="522"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
<size key="minSize" width="745" height="522"/>
<size key="minSize" width="760" height="522"/>
<size key="maxSize" width="760" height="10000000"/>
</textView>
</subviews>
</clipView>
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="2fu-s8-8On">
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="2fu-s8-8On">
<rect key="frame" x="-100" y="-100" width="225" height="15"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" verticalHuggingPriority="750" horizontal="NO" id="SXi-ew-SdF">
<rect key="frame" x="745" y="0.0" width="15" height="522"/>
<scroller key="verticalScroller" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="SXi-ew-SdF">
<rect key="frame" x="743" y="0.0" width="17" height="522"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
</scrollView>
Expand Down
12 changes: 12 additions & 0 deletions FlowVision/Sources/Common/DataModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,18 @@ class TreeViewModel {
let oldChildren=node.children
node.children=[]

// Add ".." entry to navigate up
if folderURL.path != "/" && folderURL.path != "root" {
let parentURL = folderURL.deletingLastPathComponent()
// Ensure we don't add ".." if the parent is the same as the current node
// (can happen with trailing slashes)
if parentURL.standardizedFileURL != folderURL.standardizedFileURL {
let parentNode = TreeNode(name: "..", fullPath: parentURL.absoluteString)
parentNode.hasChild = true // So it's always expandable
node.children?.append(parentNode)
}
}

for subFolder in subFolders {
var name = subFolder.lastPathComponent
var fullPath = subFolder.absoluteString
Expand Down
67 changes: 54 additions & 13 deletions FlowVision/Sources/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -611,10 +611,22 @@ class ViewController: NSViewController, NSSplitViewDelegate, NSSearchFieldDelega
largeImageView.imageView.preferredImageDynamicRange = (publicVar.isEnableHDR) ? .high : .standard
}

mainScrollView.scrollerStyle = .legacy
outlineScrollView.scrollerStyle = .legacy
// Read the custom start directory from preferences, otherwise default to home directory
let userDefaults = UserDefaults.standard
var startPath = userDefaults.string(forKey: "startDirectoryPath")

if startPath == nil || startPath!.isEmpty {
startPath = NSHomeDirectory()
} else {
// Ensure the saved path is a valid directory
var isDir: ObjCBool = false
if !FileManager.default.fileExists(atPath: startPath!, isDirectory: &isDir) || !isDir.boolValue {
startPath = NSHomeDirectory() // Fallback to home if saved path is invalid
}
}

treeViewData.initData(path: treeRootFolder)
// Initialize the tree with the determined path
treeViewData.initData(path: startPath!)
outlineView.reloadData()
DispatchQueue.main.async {
self.outlineViewManager.adjustColumnWidth()
Expand Down Expand Up @@ -986,22 +998,51 @@ class ViewController: NSViewController, NSSplitViewDelegate, NSSearchFieldDelega
}

@objc func outlineViewDoubleClicked(_ sender: AnyObject) {
// 获取当前选中的行
let row = outlineView.clickedRow

// 确保点击的是有效行
if row == -1 {
guard row != -1, let item = outlineView.item(atRow: row) as? TreeNode else {
return
}

// 获取行对应的条目
if let item = outlineView.item(atRow: row) {
if outlineView.isItemExpanded(item) {
outlineView.collapseItem(item)
} else {
outlineView.expandItem(item)
if item.name == ".." {
if let url = URL(string: item.fullPath) {
changeTreeRoot(to: url.path)
}
return
}

guard let url = URL(string: item.fullPath) else { return }

// Handle special cases like virtual tags
if url.scheme != "file" {
// This is not a filesystem path, just do the default selection action
outlineViewManager.itemSelected(item)
return
}

let path = url.path

var isDir: ObjCBool = false
if FileManager.default.fileExists(atPath: path, isDirectory: &isDir), isDir.boolValue {
changeTreeRoot(to: path)
}
}

func changeTreeRoot(to newRootPath: String) {
// Persist the new root path
UserDefaults.standard.set(newRootPath, forKey: "startDirectoryPath")

// Re-initialize the tree data model with the new path
treeViewData.initData(path: newRootPath)
outlineView.reloadData()

// Use a dispatch queue to allow the reload to complete before adjusting width
DispatchQueue.main.async {
self.outlineViewManager.adjustColumnWidth()
}

// Also switch the main view to this new root directory
let destUrl = URL(fileURLWithPath: newRootPath).absoluteString
switchDirByDirection(direction: .zero, dest: destUrl, doCollapse: false, expandLast: false, skip: false, stackDeep: 0)
}

override func viewDidLayout() {
Expand Down
24 changes: 15 additions & 9 deletions FlowVision/Sources/Views/CustomOutlineViewManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ extension CustomOutlineViewManager: NSOutlineViewDataSource {
guard let treeNode = item as? TreeNode else {
return false
}
if treeNode.name == ".." {
return false
}
if (treeNode.children?.count ?? 0) > 0 {
return true
}
Expand Down Expand Up @@ -97,16 +100,19 @@ extension CustomOutlineViewManager: NSOutlineViewDelegate {

func itemSelected(_ item: TreeNode) {
if ifActWhenSelected {
// log("Selected item: \(item.name)")
// fileDB.lock()
// let lastFolderPath = fileDB.curFolder
// fileDB.curFolder = item.fullPath
// log(fileDB.curFolder)
// fileDB.unlock()
// getViewController(self)!.publicVar.folderStepStack.insert(lastFolderPath, at: 0)
getViewController(outlineView!)?.switchDirByDirection(direction: .zero, dest: item.fullPath, doCollapse: false, expandLast: false, skip: false, stackDeep: 0)
if item.name == ".." {
// Do nothing on single click
} else {
// log("Selected item: \(item.name)")
// fileDB.lock()
// let lastFolderPath = fileDB.curFolder
// fileDB.curFolder = item.fullPath
// log(fileDB.curFolder)
// fileDB.unlock()
// getViewController(self)!.publicVar.folderStepStack.insert(lastFolderPath, at: 0)
getViewController(outlineView!)?.switchDirByDirection(direction: .zero, dest: item.fullPath, doCollapse: false, expandLast: false, skip: false, stackDeep: 0)
}
}

}
func outlineView(_ outlineView: NSOutlineView, rowViewForItem item: Any) -> NSTableRowView? {
return CustomTableRowView()
Expand Down
14 changes: 14 additions & 0 deletions pull_request_description.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Title: feat: Implement persistent, focused root directory for sidebar with '..' navigation

Description:
This Pull Request introduces a new feature to enhance sidebar management, providing more granular control over directory viewing and improving user navigation.

Key Changes:

- Custom Root Directory: Double-clicking a folder in the sidebar now sets it as the new "root" of the tree view. The sidebar will then display only the contents of that folder and its subfolders, hiding the rest of the higher hierarchy.
- Upward Navigation (`..`): If the current root directory is not the filesystem's root, a special ".." entry is added at the beginning of the list of children for the current root folder. Double-clicking ".." will navigate up one level in the directory hierarchy.
- Persistence on Launch: The selected root directory is saved in the application's preferences. Upon subsequent launches, the application will automatically start from this directory, maintaining the user's preferred sidebar configuration.

Motivation:

These changes significantly improve usability for users working with deep repositories or folder structures, allowing them to focus the directory tree on a relevant part of the filesystem and easily restore that context on each launch.