[vlc-commits] [Git][videolan/vlc][master] 40 commits: macosx: Add method to navigation sidebar view controller to get number of...

Felix Paul Kühne (@fkuehne) gitlab at videolan.org
Sat Jul 13 04:39:41 UTC 2024



Felix Paul Kühne pushed to branch master at VideoLAN / VLC


Commits:
d1b2428d by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: Add method to navigation sidebar view controller to get number of media browsing default local paths, if available

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
81fe9c90 by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: Use media sources to get local default locations

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
a69511ba by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: Move default bookmark locations into VLCLibrarySegment

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
472e4847 by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: Add a VLCLibraryBrowseBookmarkedLocationSubSegment

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
0eeda743 by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: Add a VLCLibrarySegmentBookmarkedLocation descriptor object

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
739fb3d3 by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: Support providing a bookmarked location descriptor into the represented object init of VLCLibrarySegment

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
79e74ddb by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: Correctly provide display string in vlclibrarysegment for bookmarked location segments

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
3e5c7f6a by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: Present bookmarked local locations as child nodes of the "browse" segment in sidebar

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
edbbd69c by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: Move library segment bookmarked location class definition into own file

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
6e01b90f by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: Fix library segment header comment name

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
46db6e22 by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: Add VLCLibraryBrowseBookmarkedLocationSubSegment to toolbar delegate handling

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
c77eddbc by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: Add init method to media source to initialise from a local folder MRL

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
9bad077a by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: Add method to base media source data source to present a given local folder mrl

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
4e4d185f by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: Add method to media source view controller to present a local folder via mrl

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
39a9ea1f by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: Add go to local folder mrl method in library window

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
a97dbcc5 by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: Correctly handle VLCLibraryBrowseBookmarkedLocationSubSegment in VLCLibraryWindow

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
88172f17 by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: Properly handle VLCLibrarySegments with bookmarked locations as their represented objects in the nav sidebar view controller

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
da4b2287 by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: Make sure to expand browse sidebar segment if a bookmark segment is selected

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
28109b07 by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: Add method to get index of root segments in nav sidebar view controller

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
3898eb2d by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: Find relevant segment type that needs to be expanded rather than assuming it will be at the same view index as its enum value

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
d3a33616 by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: Adapt node index fetcher to get node object directly and do BFS of available nodes

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
fd51651f by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: Don't append nodes to search if we already found a match

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
dede67da by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: Swap nil checks for node search result for one nsassert

Since we should only search for nodes of segment types that exist, just assert if we couldn't find it

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
bc9ce35f by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: Select required nodes by index by actually searching for node

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
2562d965 by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: Add initial VLCLibraryWindowNavigationSidebarOutlineView

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
7100676f by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: Make outline view in nav sidebar a VLCLibraryWindowNavigationSidebarOutlineView

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
1ddfb516 by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: Extern VLCLibraryBookmarkedLocationsKey

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
66c8eb3f by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: Add remove bookmark method to nav sidebar outline view

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
4f7ca156 by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: Add menu with "remove bookmark" for bookmark items in nav sidebar outline view

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
732402db by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: Add VLCLibraryBookmarkedLocationsChanged notification name

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
2696c86b by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: Set default bookmark locations in user defaults

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
4da70d86 by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: Fix bookmark deletion procedure in sidebar outline view, notify when done

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
8b9c9e54 by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: Fix warning about no return in sidebar outline view menu provider function

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
3a3d8da6 by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: React to bookmark location changes in nav sidebar view controller

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
cca00248 by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: Prevent changes in presented view when nav outline view reloads

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
b81e4eda by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: Reselect previous segment after reloading nav sidebar outline view

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
424f428e by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: Add bookmark method to library menu controller

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
40dd4f3d by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: Add a bookmark menu item to library menu controller for folders

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
6c6dac19 by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: Fix representedInputItems setter in library menu controller

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
6909294e by Claudio Cambra at 2024-07-13T04:18:20+00:00
macosx: Make bookmark method a toggle in library menu controller

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -


21 changed files:

- extras/package/macosx/VLC.xcodeproj/project.pbxproj
- modules/gui/macosx/Makefile.am
- modules/gui/macosx/UI/VLCLibraryWindowNavigationSidebarView.xib
- modules/gui/macosx/library/VLCLibraryMenuController.m
- modules/gui/macosx/library/VLCLibrarySegment.h
- modules/gui/macosx/library/VLCLibrarySegment.m
- + modules/gui/macosx/library/VLCLibrarySegmentBookmarkedLocation.h
- + modules/gui/macosx/library/VLCLibrarySegmentBookmarkedLocation.m
- modules/gui/macosx/library/VLCLibraryWindow.h
- modules/gui/macosx/library/VLCLibraryWindow.m
- + modules/gui/macosx/library/VLCLibraryWindowNavigationSidebarOutlineView.h
- + modules/gui/macosx/library/VLCLibraryWindowNavigationSidebarOutlineView.m
- modules/gui/macosx/library/VLCLibraryWindowNavigationSidebarViewController.h
- modules/gui/macosx/library/VLCLibraryWindowNavigationSidebarViewController.m
- modules/gui/macosx/library/VLCLibraryWindowToolbarDelegate.m
- modules/gui/macosx/library/media-source/VLCLibraryMediaSourceViewController.h
- modules/gui/macosx/library/media-source/VLCLibraryMediaSourceViewController.m
- modules/gui/macosx/library/media-source/VLCMediaSource.h
- modules/gui/macosx/library/media-source/VLCMediaSource.m
- modules/gui/macosx/library/media-source/VLCMediaSourceBaseDataSource.h
- modules/gui/macosx/library/media-source/VLCMediaSourceBaseDataSource.m


Changes:

=====================================
extras/package/macosx/VLC.xcodeproj/project.pbxproj
=====================================
@@ -83,6 +83,8 @@
 		531343E72A8E7B94007AEDFA /* VLCLibraryWindowNavigationSidebarViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 531343E62A8E7B94007AEDFA /* VLCLibraryWindowNavigationSidebarViewController.m */; };
 		531343EA2A8E8965007AEDFA /* VLCLibrarySegment.m in Sources */ = {isa = PBXBuildFile; fileRef = 531343E92A8E8965007AEDFA /* VLCLibrarySegment.m */; };
 		5317FE04294E3DD3001702F0 /* VLCLibraryCollectionViewDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 5317FE03294E3DD3001702F0 /* VLCLibraryCollectionViewDelegate.m */; };
+		532572032C3D79D80068DEC3 /* VLCLibrarySegmentBookmarkedLocation.m in Sources */ = {isa = PBXBuildFile; fileRef = 532572022C3D79D80068DEC3 /* VLCLibrarySegmentBookmarkedLocation.m */; };
+		532572062C3EF3710068DEC3 /* VLCLibraryWindowNavigationSidebarOutlineView.m in Sources */ = {isa = PBXBuildFile; fileRef = 532572052C3EF3710068DEC3 /* VLCLibraryWindowNavigationSidebarOutlineView.m */; };
 		5325C57D29302E6800B2B63A /* VLCLibraryAudioViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5325C57B29302E6800B2B63A /* VLCLibraryAudioViewController.m */; };
 		533B5D2C29CF94C6003DE887 /* VLCBookmarksTableViewDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 533B5D2B29CF94C6003DE887 /* VLCBookmarksTableViewDataSource.m */; };
 		534E73E229D2EDB1009982DE /* VLCBookmarksTableViewDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 534E73E129D2EDB1009982DE /* VLCBookmarksTableViewDelegate.m */; };
@@ -294,6 +296,10 @@
 		5317FE02294E3DD3001702F0 /* VLCLibraryCollectionViewDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VLCLibraryCollectionViewDelegate.h; sourceTree = "<group>"; };
 		5317FE03294E3DD3001702F0 /* VLCLibraryCollectionViewDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VLCLibraryCollectionViewDelegate.m; sourceTree = "<group>"; };
 		5317FE05294E8D1A001702F0 /* VLCLibraryCollectionViewDataSource.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VLCLibraryCollectionViewDataSource.h; sourceTree = "<group>"; };
+		532572012C3D79D80068DEC3 /* VLCLibrarySegmentBookmarkedLocation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VLCLibrarySegmentBookmarkedLocation.h; sourceTree = "<group>"; };
+		532572022C3D79D80068DEC3 /* VLCLibrarySegmentBookmarkedLocation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VLCLibrarySegmentBookmarkedLocation.m; sourceTree = "<group>"; };
+		532572042C3EF3710068DEC3 /* VLCLibraryWindowNavigationSidebarOutlineView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VLCLibraryWindowNavigationSidebarOutlineView.h; sourceTree = "<group>"; };
+		532572052C3EF3710068DEC3 /* VLCLibraryWindowNavigationSidebarOutlineView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VLCLibraryWindowNavigationSidebarOutlineView.m; sourceTree = "<group>"; };
 		5325C57B29302E6800B2B63A /* VLCLibraryAudioViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VLCLibraryAudioViewController.m; sourceTree = "<group>"; };
 		5325C57C29302E6800B2B63A /* VLCLibraryAudioViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VLCLibraryAudioViewController.h; sourceTree = "<group>"; };
 		533B5D2A29CF94C6003DE887 /* VLCBookmarksTableViewDataSource.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VLCBookmarksTableViewDataSource.h; sourceTree = "<group>"; };
@@ -1310,6 +1316,8 @@
 				530771F32AEBBD5B00656D3D /* VLCLibraryRepresentedItem.m */,
 				531343E82A8E8965007AEDFA /* VLCLibrarySegment.h */,
 				531343E92A8E8965007AEDFA /* VLCLibrarySegment.m */,
+				532572012C3D79D80068DEC3 /* VLCLibrarySegmentBookmarkedLocation.h */,
+				532572022C3D79D80068DEC3 /* VLCLibrarySegmentBookmarkedLocation.m */,
 				7D22A8F222BC14F80063ECD2 /* VLCLibrarySortingMenuController.h */,
 				7D22A8F322BC14F80063ECD2 /* VLCLibrarySortingMenuController.m */,
 				7DE2F0452282D5D10040DD0A /* VLCLibraryTableCellView.h */,
@@ -1328,6 +1336,8 @@
 				7D713D312201AE350042BEB7 /* VLCLibraryWindow.m */,
 				5362550B293FD639005D64FA /* VLCLibraryWindowController.h */,
 				5362550C293FD639005D64FA /* VLCLibraryWindowController.m */,
+				532572042C3EF3710068DEC3 /* VLCLibraryWindowNavigationSidebarOutlineView.h */,
+				532572052C3EF3710068DEC3 /* VLCLibraryWindowNavigationSidebarOutlineView.m */,
 				531343E52A8E7B94007AEDFA /* VLCLibraryWindowNavigationSidebarViewController.h */,
 				531343E62A8E7B94007AEDFA /* VLCLibraryWindowNavigationSidebarViewController.m */,
 				5352B37429E149AC0011CE03 /* VLCLibraryWindowPersistentPreferences.h */,
@@ -2102,6 +2112,7 @@
 				1CCC89012078A3D500E5626F /* Preferences.xib in Sources */,
 				7DC21A7422049A6600F98A02 /* VLCOpenInputMetadata.m in Sources */,
 				1CCC89022078A3D500E5626F /* ResumeDialog.xib in Sources */,
+				532572032C3D79D80068DEC3 /* VLCLibrarySegmentBookmarkedLocation.m in Sources */,
 				7DE7232E22A51F8D00D72616 /* VLCPositionFormatter.m in Sources */,
 				534E8E3A29A06325009503F8 /* VLCMainVideoViewController.m in Sources */,
 				536EFBF5295BCB8300F4CB13 /* VLCLibraryUIUnits.m in Sources */,
@@ -2131,6 +2142,7 @@
 				1C3113EF1E508C7600D4DD76 /* VLCRendererDiscovery.m in Sources */,
 				1C3113F11E508C7600D4DD76 /* VLCRendererItem.m in Sources */,
 				1C3113F31E508C7600D4DD76 /* VLCRendererMenuController.m in Sources */,
+				532572062C3EF3710068DEC3 /* VLCLibraryWindowNavigationSidebarOutlineView.m in Sources */,
 				53ED473629CA4F3400795DB1 /* VLCLibraryTableViewDelegate.m in Sources */,
 				6B4D50931E7979CB004479B5 /* VLCSimplePrefsWindow.m in Sources */,
 				6B397C4F216C8EB200403ED0 /* NSString+Helpers.m in Sources */,


=====================================
modules/gui/macosx/Makefile.am
=====================================
@@ -135,6 +135,8 @@ libmacosx_plugin_la_SOURCES = \
 	gui/macosx/library/VLCLibraryRepresentedItem.m \
 	gui/macosx/library/VLCLibrarySegment.h \
 	gui/macosx/library/VLCLibrarySegment.m \
+	gui/macosx/library/VLCLibrarySegmentBookmarkedLocation.h \
+	gui/macosx/library/VLCLibrarySegmentBookmarkedLocation.m \
 	gui/macosx/library/VLCLibrarySortingMenuController.h \
 	gui/macosx/library/VLCLibrarySortingMenuController.m \
 	gui/macosx/library/VLCLibraryTableView.h \
@@ -153,6 +155,8 @@ libmacosx_plugin_la_SOURCES = \
 	gui/macosx/library/VLCLibraryWindow.m \
 	gui/macosx/library/VLCLibraryWindowController.h \
 	gui/macosx/library/VLCLibraryWindowController.m \
+	gui/macosx/library/VLCLibraryWindowNavigationSidebarOutlineView.h \
+	gui/macosx/library/VLCLibraryWindowNavigationSidebarOutlineView.m \
 	gui/macosx/library/VLCLibraryWindowNavigationSidebarViewController.h \
 	gui/macosx/library/VLCLibraryWindowNavigationSidebarViewController.m \
 	gui/macosx/library/VLCLibraryWindowPersistentPreferences.h \


=====================================
modules/gui/macosx/UI/VLCLibraryWindowNavigationSidebarView.xib
=====================================
@@ -7,7 +7,7 @@
     <objects>
         <customObject id="-2" userLabel="File's Owner" customClass="VLCLibraryWindowNavigationSidebarViewController">
             <connections>
-                <outlet property="outlineView" destination="7u8-Zm-gnd" id="sWc-AU-MVa"/>
+                <outlet property="outlineView" destination="7u8-Zm-gnd" id="8i3-ld-a1v"/>
                 <outlet property="view" destination="gLW-4d-ery" id="lAX-ki-W5E"/>
             </connections>
         </customObject>
@@ -20,7 +20,7 @@
                 <rect key="frame" x="0.0" y="0.0" width="52" height="408"/>
                 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                 <subviews>
-                    <outlineView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" selectionHighlightStyle="sourceList" multipleSelection="NO" autosaveColumns="NO" rowSizeStyle="automatic" viewBased="YES" floatsGroupRows="NO" indentationPerLevel="13" outlineTableColumn="0BA-rc-l73" id="7u8-Zm-gnd">
+                    <outlineView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" selectionHighlightStyle="sourceList" multipleSelection="NO" autosaveColumns="NO" rowSizeStyle="automatic" viewBased="YES" floatsGroupRows="NO" indentationPerLevel="13" outlineTableColumn="0BA-rc-l73" id="7u8-Zm-gnd" customClass="VLCLibraryWindowNavigationSidebarOutlineView">
                         <rect key="frame" x="0.0" y="0.0" width="52" height="408"/>
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <size key="intercellSpacing" width="3" height="0.0"/>


=====================================
modules/gui/macosx/library/VLCLibraryMenuController.m
=====================================
@@ -28,6 +28,7 @@
 #import "library/VLCInputItem.h"
 #import "library/VLCLibraryController.h"
 #import "library/VLCLibraryRepresentedItem.h"
+#import "library/VLCLibrarySegment.h"
 
 #import "main/VLCMain.h"
 
@@ -45,6 +46,7 @@
     NSHashTable<NSMenuItem*> *_mediaItemRequiringMenuItems;
     NSHashTable<NSMenuItem*> *_inputItemRequiringMenuItems;
     NSHashTable<NSMenuItem*> *_localInputItemRequiringMenuItems;
+    NSHashTable<NSMenuItem*> *_folderInputItemRequiringMenuItems;
 }
 @end
 
@@ -79,8 +81,22 @@
     NSMenuItem *informationItem = [[NSMenuItem alloc] initWithTitle:_NS("Information...") action:@selector(showInformation:) keyEquivalent:@""];
     informationItem.target = self;
 
+    NSMenuItem * const bookmarkItem = [[NSMenuItem alloc] initWithTitle:_NS("Toggle Bookmark")
+                                                                 action:@selector(toggleBookmark:)
+                                                          keyEquivalent:@""];
+    bookmarkItem.target = self;
+
     _libraryMenu = [[NSMenu alloc] initWithTitle:@""];
-    [_libraryMenu addMenuItemsFromArray:@[playItem, appendItem, revealItem, deleteItem, informationItem, [NSMenuItem separatorItem], addItem]];
+    [_libraryMenu addMenuItemsFromArray:@[
+        playItem,
+        appendItem,
+        bookmarkItem,
+        revealItem,
+        deleteItem,
+        informationItem,
+        [NSMenuItem separatorItem], 
+        addItem
+    ]];
 
     _mediaItemRequiringMenuItems = [NSHashTable weakObjectsHashTable];
     [_mediaItemRequiringMenuItems addObject:playItem];
@@ -96,12 +112,15 @@
     _localInputItemRequiringMenuItems = [NSHashTable weakObjectsHashTable];
     [_localInputItemRequiringMenuItems addObject:revealItem];
     [_localInputItemRequiringMenuItems addObject:deleteItem];
+
+    _folderInputItemRequiringMenuItems = [NSHashTable weakObjectsHashTable];
+    [_folderInputItemRequiringMenuItems addObject:bookmarkItem];
 }
 
 - (void)menuItems:(NSHashTable<NSMenuItem*>*)menuItems
         setHidden:(BOOL)hidden
 {
-    for (NSMenuItem *menuItem in menuItems) {
+    for (NSMenuItem * const menuItem in menuItems) {
         menuItem.hidden = hidden;
     }
 }
@@ -111,6 +130,7 @@
     if (self.representedItems != nil && self.representedItems.count > 0) {
         [self menuItems:_inputItemRequiringMenuItems setHidden:YES];
         [self menuItems:_localInputItemRequiringMenuItems setHidden:YES];
+        [self menuItems:_folderInputItemRequiringMenuItems setHidden:YES];
         [self menuItems:_mediaItemRequiringMenuItems setHidden:NO];
     } else if (_representedInputItems != nil && self.representedInputItems.count > 0) {
         [self menuItems:_mediaItemRequiringMenuItems setHidden:YES];
@@ -123,7 +143,13 @@
                 break;
             }
         }
+
+        const BOOL bookmarkable =
+            self.representedInputItems.count == 1 &&
+            self.representedInputItems.firstObject.inputType == ITEM_TYPE_DIRECTORY;
+
         [self menuItems:_localInputItemRequiringMenuItems setHidden:anyStream];
+        [self menuItems:_folderInputItemRequiringMenuItems setHidden:!bookmarkable];
    }
 }
 
@@ -234,6 +260,30 @@
     [_informationWindowController toggleWindow:sender];
 }
 
+- (void)toggleBookmark:(id)sender
+{
+    if (self.representedInputItems == nil || 
+        self.representedInputItems.count != 1 ||
+        self.representedInputItems.firstObject.inputType != ITEM_TYPE_DIRECTORY) {
+        return;
+    }
+
+    VLCInputItem * const inputItem = self.representedInputItems.firstObject;
+    NSString * const inputItemMRL = inputItem.MRL;
+    NSUserDefaults * const defaults = NSUserDefaults.standardUserDefaults;
+    NSMutableArray<NSString *> * const bookmarkedLocations =
+        [defaults stringArrayForKey:VLCLibraryBookmarkedLocationsKey].mutableCopy;
+    NSNotificationCenter * const defaultCenter = NSNotificationCenter.defaultCenter;
+
+    if ([bookmarkedLocations containsObject:inputItemMRL]) {
+        [bookmarkedLocations removeObject:inputItemMRL];
+    } else {
+        [bookmarkedLocations addObject:inputItemMRL];
+    }
+    [defaults setObject:bookmarkedLocations forKey:VLCLibraryBookmarkedLocationsKey];
+    [defaultCenter postNotificationName:VLCLibraryBookmarkedLocationsChanged object:inputItemMRL];
+}
+
 - (void)setRepresentedItems:(NSArray<VLCLibraryRepresentedItem *> *)items
 {
     _representedItems = items;
@@ -241,7 +291,7 @@
     [self updateMenuItems];
 }
 
-- (void)setRepresentedInputItem:(NSArray<VLCInputItem *> *)representedInputItems
+- (void)setRepresentedInputItems:(NSArray<VLCInputItem *> *)representedInputItems
 {
     _representedInputItems = representedInputItems;
     _representedItems = nil;


=====================================
modules/gui/macosx/library/VLCLibrarySegment.h
=====================================
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * VLCLibrarySection.h: MacOS X interface module
+ * VLCLibrarySegment.h: MacOS X interface module
  *****************************************************************************
  * Copyright (C) 2023 VLC authors and VideoLAN
  *
@@ -24,6 +24,9 @@
 
 NS_ASSUME_NONNULL_BEGIN
 
+extern NSString * const VLCLibraryBookmarkedLocationsKey;
+extern NSString * const VLCLibraryBookmarkedLocationsChanged;
+
 typedef NS_ENUM(NSInteger, VLCLibrarySegmentType) {
     VLCLibraryLowSentinelSegment = -1,
     VLCLibraryHomeSegment,
@@ -34,6 +37,7 @@ typedef NS_ENUM(NSInteger, VLCLibrarySegmentType) {
     VLCLibrarySongsMusicSubSegment,
     VLCLibraryGenresMusicSubSegment,
     VLCLibraryBrowseSegment,
+    VLCLibraryBrowseBookmarkedLocationSubSegment,
     VLCLibraryStreamsSegment,
     VLCLibraryHighSentinelSegment,
 };


=====================================
modules/gui/macosx/library/VLCLibrarySegment.m
=====================================
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * VLCLibrarySection.h: MacOS X interface module
+ * VLCLibrarySegment.m: MacOS X interface module
  *****************************************************************************
  * Copyright (C) 2023 VLC authors and VideoLAN
  *
@@ -24,6 +24,15 @@
 
 #import "extensions/NSString+Helpers.h"
 
+#import "library/VLCInputItem.h"
+#import "library/VLCLibrarySegmentBookmarkedLocation.h"
+
+#import "library/media-source/VLCMediaSource.h"
+#import "library/media-source/VLCMediaSourceProvider.h"
+
+NSString * const VLCLibraryBookmarkedLocationsKey = @"VLCLibraryBookmarkedLocations";
+NSString * const VLCLibraryBookmarkedLocationsChanged = @"VLCLibraryBookmarkedLocationsChanged";
+
 @implementation VLCLibrarySegment
 
 + (NSArray<VLCLibrarySegment *> *)librarySegments
@@ -49,10 +58,18 @@
 
 - (instancetype)initWithRepresentedObject:(id)modelObject
 {
-    NSNumber * const segmentNumber = (NSNumber *)modelObject;
-    const NSInteger segmentValue = segmentNumber.integerValue;
-    NSAssert(segmentNumber != nil &&
-             segmentValue > VLCLibraryLowSentinelSegment &&
+    NSInteger segmentValue = VLCLibraryLowSentinelSegment;
+
+    if ([modelObject isKindOfClass:NSNumber.class]) {
+        NSNumber * const segmentNumber = (NSNumber *)modelObject;
+        segmentValue = segmentNumber.integerValue;
+    } else if ([modelObject isKindOfClass:VLCLibrarySegmentBookmarkedLocation.class]) {
+        VLCLibrarySegmentBookmarkedLocation * const descriptor =
+            (VLCLibrarySegmentBookmarkedLocation *)modelObject;
+        segmentValue = descriptor.segmentType;
+    }
+
+    NSAssert(segmentValue > VLCLibraryLowSentinelSegment &&
              segmentValue < VLCLibraryHighSentinelSegment,
              @"VLCLibrarySegment represented object must be a library segment type value!");
 
@@ -66,16 +83,58 @@
 
 - (NSArray<NSTreeNode *> *)childNodes
 {
-    if (self.segmentType != VLCLibraryMusicSegment) {
-        return nil;
+    if (self.segmentType == VLCLibraryMusicSegment) {
+        return @[
+            [VLCLibrarySegment segmentWithSegmentType:VLCLibraryArtistsMusicSubSegment],
+            [VLCLibrarySegment segmentWithSegmentType:VLCLibraryAlbumsMusicSubSegment],
+            [VLCLibrarySegment segmentWithSegmentType:VLCLibrarySongsMusicSubSegment],
+            [VLCLibrarySegment segmentWithSegmentType:VLCLibraryGenresMusicSubSegment],
+        ];
+    } else if (self.segmentType == VLCLibraryBrowseSegment) {
+        NSUserDefaults * const defaults = NSUserDefaults.standardUserDefaults;
+        NSArray<NSString *> *bookmarkedLocations =
+            [defaults stringArrayForKey:VLCLibraryBookmarkedLocationsKey];
+        if (bookmarkedLocations == nil) {
+            bookmarkedLocations = self.defaultBookmarkedLocations;
+            [defaults setObject:bookmarkedLocations forKey:VLCLibraryBookmarkedLocationsKey];
+        }
+
+        const VLCLibrarySegmentType segmentType = VLCLibraryBrowseBookmarkedLocationSubSegment;
+        NSMutableArray<NSTreeNode *> * const bookmarkedLocationNodes = NSMutableArray.array;
+
+        for (NSString * const locationMrl in bookmarkedLocations) {
+            NSString * const locationName = locationMrl.lastPathComponent;
+            VLCLibrarySegmentBookmarkedLocation * const descriptor =
+                [[VLCLibrarySegmentBookmarkedLocation alloc] initWithSegmentType:segmentType
+                                                                            name:locationName
+                                                                             mrl:locationMrl];
+            VLCLibrarySegment * const node = 
+                [VLCLibrarySegment treeNodeWithRepresentedObject:descriptor];
+            [bookmarkedLocationNodes addObject:node];
+        }
+
+        return bookmarkedLocationNodes.copy;
     }
-    
-    return @[
-        [VLCLibrarySegment segmentWithSegmentType:VLCLibraryArtistsMusicSubSegment],
-        [VLCLibrarySegment segmentWithSegmentType:VLCLibraryAlbumsMusicSubSegment],
-        [VLCLibrarySegment segmentWithSegmentType:VLCLibrarySongsMusicSubSegment],
-        [VLCLibrarySegment segmentWithSegmentType:VLCLibraryGenresMusicSubSegment],
-    ];
+
+    return nil;
+}
+
+- (NSArray<NSString *> *)defaultBookmarkedLocations
+{
+    NSMutableArray<NSString *> * const locationMrls = NSMutableArray.array;
+    NSArray<VLCMediaSource *> * const localMediaSources =
+        VLCMediaSourceProvider.listOfLocalMediaSources;
+
+    for (VLCMediaSource * const mediaSource in localMediaSources) {
+        VLCInputNode * const rootNode = mediaSource.rootNode;
+        [mediaSource preparseInputNodeWithinTree:rootNode];
+
+        for (VLCInputNode * const node in rootNode.children) {
+            [locationMrls addObject:node.inputItem.MRL];
+        }
+    }
+
+    return locationMrls.copy;
 }
 
 - (NSInteger)childCount
@@ -102,6 +161,8 @@
             return _NS("Videos");
         case VLCLibraryBrowseSegment:
             return _NS("Browse");
+        case VLCLibraryBrowseBookmarkedLocationSubSegment:
+            NSAssert(true, @"displayStringForType should not be called for this segment type");
         case VLCLibraryStreamsSegment:
             return _NS("Streams");
         case VLCLibraryLowSentinelSegment:
@@ -126,6 +187,7 @@
         case VLCLibraryVideoSegment:
             return [NSImage imageNamed:@"sidebar-movie"];
         case VLCLibraryBrowseSegment:
+        case VLCLibraryBrowseBookmarkedLocationSubSegment:
             return [NSImage imageNamed:@"NSFolder"];
         case VLCLibraryStreamsSegment:
             return [NSImage imageNamed:@"NSActionTemplate"];
@@ -163,6 +225,9 @@
         case VLCLibraryBrowseSegment:
             return [NSImage imageWithSystemSymbolName:@"folder"
                              accessibilityDescription:@"Browse icon"];
+        case VLCLibraryBrowseBookmarkedLocationSubSegment:
+            return [NSImage imageWithSystemSymbolName:@"folder"
+                             accessibilityDescription:@"Bookmarked location icon"];
         case VLCLibraryStreamsSegment:
             return [NSImage imageWithSystemSymbolName:@"antenna.radiowaves.left.and.right"
                              accessibilityDescription:@"Streams icon"];
@@ -190,7 +255,13 @@
 
 - (void)updateSegmentTypeRepresentation
 {
-    _displayString = [self displayStringForType:_segmentType];
+    if ([self.representedObject isKindOfClass:VLCLibrarySegmentBookmarkedLocation.class]) {
+        VLCLibrarySegmentBookmarkedLocation * const descriptor =
+            (VLCLibrarySegmentBookmarkedLocation *)self.representedObject;
+        _displayString = descriptor.name;
+    } else {
+        _displayString = [self displayStringForType:_segmentType];
+    }
     _displayImage = [self iconForType:_segmentType];
 }
 


=====================================
modules/gui/macosx/library/VLCLibrarySegmentBookmarkedLocation.h
=====================================
@@ -0,0 +1,39 @@
+/*****************************************************************************
+ * VLCLibrarySegmentBookmarkedLocation.h: MacOS X interface module
+ *****************************************************************************
+ * Copyright (C) 2024 VLC authors and VideoLAN
+ *
+ * Authors: Claudio Cambra <developer at claudiocambra.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#import "library/VLCLibrarySegment.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+ at interface VLCLibrarySegmentBookmarkedLocation : NSObject
+
+ at property (readonly) VLCLibrarySegmentType segmentType;
+ at property (readonly) NSString *name;
+ at property (readonly) NSString *mrl;
+
+- (instancetype)initWithSegmentType:(VLCLibrarySegmentType)segmentType
+                               name:(NSString *)name
+                                mrl:(NSString *)mrl;
+
+ at end
+
+NS_ASSUME_NONNULL_END


=====================================
modules/gui/macosx/library/VLCLibrarySegmentBookmarkedLocation.m
=====================================
@@ -0,0 +1,40 @@
+/*****************************************************************************
+ * VLCLibrarySegmentBookmarkedLocation.h: MacOS X interface module
+ *****************************************************************************
+ * Copyright (C) 2024 VLC authors and VideoLAN
+ *
+ * Authors: Claudio Cambra <developer at claudiocambra.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#import "VLCLibrarySegmentBookmarkedLocation.h"
+
+ at implementation VLCLibrarySegmentBookmarkedLocation
+
+- (instancetype)initWithSegmentType:(VLCLibrarySegmentType)segmentType
+                               name:(NSString *)name
+                                mrl:(NSString *)mrl
+{
+    self = [super init];
+    if (self) {
+        _segmentType = segmentType;
+        _name = name;
+        _mrl = mrl;
+    }
+    return self;
+}
+
+ at end


=====================================
modules/gui/macosx/library/VLCLibraryWindow.h
=====================================
@@ -135,6 +135,7 @@ extern const NSUserInterfaceItemIdentifier VLCLibraryWindowIdentifier;
 - (void)clearFilterString;
 
 - (void)presentLibraryItem:(id<VLCMediaLibraryItemProtocol>)libraryItem;
+- (void)goToLocalFolderMrl:(NSString *)mrl;
 
 - (IBAction)goToBrowseSection:(id)sender;
 - (IBAction)sortLibrary:(id)sender;


=====================================
modules/gui/macosx/library/VLCLibraryWindow.m
=====================================
@@ -257,6 +257,7 @@ static void addShadow(NSImageView *__unsafe_unretained imageView)
         [self showAudioLibrary];
         break;
     case VLCLibraryBrowseSegment:
+    case VLCLibraryBrowseBookmarkedLocationSubSegment:
     case VLCLibraryStreamsSegment:
         [self showMediaSourceLibrary];
         break;
@@ -309,6 +310,7 @@ static void addShadow(NSImageView *__unsafe_unretained imageView)
         preferences.songsLibraryViewMode = _currentSelectedViewModeSegment;
         break;
     case VLCLibraryBrowseSegment:
+    case VLCLibraryBrowseBookmarkedLocationSubSegment:
         preferences.browseLibraryViewMode = _currentSelectedViewModeSegment;
         break;
     case VLCLibraryStreamsSegment:
@@ -389,6 +391,12 @@ static void addShadow(NSImageView *__unsafe_unretained imageView)
     NSLog(@"Unknown kind of library item provided, cannot present library view for it: %@", libraryItem.displayString);
 }
 
+- (void)goToLocalFolderMrl:(NSString *)mrl
+{
+    [self goToBrowseSection:self];
+    [self.libraryMediaSourceViewController presentLocalFolderMrl:mrl];
+}
+
 - (IBAction)sortLibrary:(id)sender
 {
     if (!_librarySortingMenuController) {


=====================================
modules/gui/macosx/library/VLCLibraryWindowNavigationSidebarOutlineView.h
=====================================
@@ -0,0 +1,31 @@
+/*****************************************************************************
+ * VLCLibraryWindowNavigationSidebarOutlineView.h: MacOS X interface module
+ *****************************************************************************
+ * Copyright (C) 2024 VLC authors and VideoLAN
+ *
+ * Authors: Claudio Cambra <developer at claudiocambra.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#import <Cocoa/Cocoa.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+ at interface VLCLibraryWindowNavigationSidebarOutlineView : NSOutlineView
+
+ at end
+
+NS_ASSUME_NONNULL_END


=====================================
modules/gui/macosx/library/VLCLibraryWindowNavigationSidebarOutlineView.m
=====================================
@@ -0,0 +1,79 @@
+/*****************************************************************************
+ * VLCLibraryWindowNavigationSidebarOutlineView.m: MacOS X interface module
+ *****************************************************************************
+ * Copyright (C) 2024 VLC authors and VideoLAN
+ *
+ * Authors: Claudio Cambra <developer at claudiocambra.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#import "VLCLibraryWindowNavigationSidebarOutlineView.h"
+
+#import "extensions/NSString+Helpers.h"
+
+#import "library/VLCLibrarySegment.h"
+#import "library/VLCLibrarySegmentBookmarkedLocation.h"
+
+ at implementation VLCLibraryWindowNavigationSidebarOutlineView
+
+- (NSMenu *)menuForEvent:(NSEvent *)event
+{
+    const NSPoint location = [self convertPoint:event.locationInWindow fromView:nil];
+    const NSInteger row = [self rowAtPoint:location];
+    NSTreeNode * const node = [self itemAtRow:row];
+    VLCLibrarySegment * const segment = node.representedObject;
+    
+    if ([segment.representedObject isKindOfClass:NSNumber.class]) {
+        return nil;
+    }
+
+    if ([segment.representedObject isKindOfClass:VLCLibrarySegmentBookmarkedLocation.class]) {
+        VLCLibrarySegmentBookmarkedLocation * const descriptor = segment.representedObject;
+        NSMenu * const bookmarkMenu = [[NSMenu alloc] initWithTitle:descriptor.name];
+        NSMenuItem * const removeBookmarkItem = 
+            [[NSMenuItem alloc] initWithTitle:_NS("Remove Bookmark")
+                                       action:@selector(removeBookmark:)
+                                keyEquivalent:@""];
+        removeBookmarkItem.representedObject = descriptor;
+        [bookmarkMenu addItem:removeBookmarkItem];
+        return bookmarkMenu;
+    }
+
+    return nil;
+}
+
+- (void)removeBookmark:(id)sender
+{
+    NSMenuItem * const menuItem = sender;
+    NSParameterAssert(menuItem != nil);
+
+    VLCLibrarySegmentBookmarkedLocation * const descriptor = menuItem.representedObject;
+    NSParameterAssert(descriptor != nil);
+
+    NSString * const descriptorMrl = descriptor.mrl;
+    NSParameterAssert(descriptorMrl != nil);
+
+    NSUserDefaults * const defaults = NSUserDefaults.standardUserDefaults;
+    NSMutableArray<NSString *> * const bookmarkedLocations =
+        [defaults stringArrayForKey:VLCLibraryBookmarkedLocationsKey].mutableCopy;
+    [bookmarkedLocations removeObject:descriptorMrl];
+    [defaults setObject:bookmarkedLocations forKey:VLCLibraryBookmarkedLocationsKey];
+
+    NSNotificationCenter * const defaultCenter = NSNotificationCenter.defaultCenter;
+    [defaultCenter postNotificationName:VLCLibraryBookmarkedLocationsChanged object:descriptor];
+}
+
+ at end


=====================================
modules/gui/macosx/library/VLCLibraryWindowNavigationSidebarViewController.h
=====================================
@@ -25,6 +25,7 @@
 NS_ASSUME_NONNULL_BEGIN
 
 @class VLCLibraryWindow;
+ at class VLCLibraryWindowNavigationSidebarOutlineView;
 @class VLCLibrarySegment;
 
 @interface VLCLibraryWindowNavigationSidebarViewController : NSViewController<NSOutlineViewDelegate>
@@ -33,7 +34,7 @@ NS_ASSUME_NONNULL_BEGIN
 @property (readonly) NSArray<VLCLibrarySegment *> *segments;
 @property (readonly) NSTreeController *treeController;
 
- at property (readwrite, weak) IBOutlet NSOutlineView *outlineView;
+ at property (readwrite, weak) IBOutlet VLCLibraryWindowNavigationSidebarOutlineView *outlineView;
 
 - (instancetype)initWithLibraryWindow:(VLCLibraryWindow *)libraryWindow;
 - (void)selectSegment:(NSInteger)segmentType;


=====================================
modules/gui/macosx/library/VLCLibraryWindowNavigationSidebarViewController.m
=====================================
@@ -23,11 +23,19 @@
 #import "VLCLibraryWindowNavigationSidebarViewController.h"
 
 #import "library/VLCLibraryWindow.h"
+#import "library/VLCLibraryWindowNavigationSidebarOutlineView.h"
 #import "library/VLCLibrarySegment.h"
+#import "library/VLCLibrarySegmentBookmarkedLocation.h"
 
 // This needs to match whatever identifier has been set in the library window XIB
 static NSString * const VLCLibrarySegmentCellIdentifier = @"VLCLibrarySegmentCellIdentifier";
 
+ at interface VLCLibraryWindowNavigationSidebarViewController ()
+
+ at property BOOL ignoreSegmentSelectionChanges;
+
+ at end
+
 @implementation VLCLibraryWindowNavigationSidebarViewController
 
 - (instancetype)initWithLibraryWindow:(VLCLibraryWindow *)libraryWindow
@@ -36,6 +44,7 @@ static NSString * const VLCLibrarySegmentCellIdentifier = @"VLCLibrarySegmentCel
     if (self) {
         _libraryWindow = libraryWindow;
         _segments = VLCLibrarySegment.librarySegments;
+        _ignoreSegmentSelectionChanges = NO;
     }
     return self;
 }
@@ -61,6 +70,56 @@ static NSString * const VLCLibrarySegmentCellIdentifier = @"VLCLibrarySegmentCel
                options:nil];
 
     [_outlineView reloadData];
+
+    NSNotificationCenter * const defaultCenter = NSNotificationCenter.defaultCenter;
+    [defaultCenter addObserver:self
+                      selector:@selector(bookmarkedLocationsChanged:)
+                          name:VLCLibraryBookmarkedLocationsChanged
+                        object:nil];
+}
+
+- (void)bookmarkedLocationsChanged:(NSNotification *)notification
+{
+    const VLCLibrarySegmentType currentSegmentType = self.libraryWindow.librarySegmentType;
+
+    self.ignoreSegmentSelectionChanges = YES;
+    
+    [self.treeController rearrangeObjects];
+    [self.outlineView reloadData];
+
+    NSTreeNode * const targetNode = [self nodeForSegmentType:currentSegmentType];
+    const NSInteger segmentIndex = [self.outlineView rowForItem:targetNode];
+    [self.outlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:segmentIndex]
+                  byExtendingSelection:NO];
+
+    self.ignoreSegmentSelectionChanges = NO;
+}
+
+- (NSTreeNode *)nodeForSegmentType:(VLCLibrarySegmentType)segmentType
+{
+    NSArray<NSTreeNode *> *nodes = self.treeController.arrangedObjects.childNodes;
+    while (nodes.count != 0) {
+        NSMutableArray<NSTreeNode *> * const nextLevelNodes = NSMutableArray.array;
+
+        const NSInteger nodeIdx = [nodes indexOfObjectPassingTest:^BOOL(NSTreeNode * const obj,
+                                                                        NSUInteger idx,
+                                                                        BOOL * const stop) {
+            VLCLibrarySegment * const segment = obj.representedObject;
+            const BOOL matching = segment.segmentType == segmentType;
+            if (!matching) {
+                [nextLevelNodes addObjectsFromArray:obj.childNodes];
+            }
+            return matching;
+        }];
+
+        if (nodeIdx != NSNotFound) {
+            return nodes[nodeIdx];
+        }
+
+        nodes = nextLevelNodes.copy;
+    }
+    NSAssert(NO, @"Could not find node for segment type %ld", segmentType);
+    return nil;
 }
 
 - (void)selectSegment:(NSInteger)segmentType
@@ -72,12 +131,16 @@ static NSString * const VLCLibrarySegmentCellIdentifier = @"VLCLibrarySegmentCel
     VLCLibrarySegment * const segment = [VLCLibrarySegment segmentWithSegmentType:segmentType];
     self.libraryWindow.librarySegmentType = segment.segmentType;
 
-    if (segmentType >= VLCLibraryMusicSegment) {
-        NSTreeNode * const itemNode = (NSTreeNode *)[_outlineView itemAtRow:VLCLibraryMusicSegment];
-        [self.outlineView expandItem:itemNode];
+    if (segmentType >= VLCLibraryMusicSegment && segmentType <= VLCLibraryGenresMusicSubSegment) {
+        [self.outlineView expandItem:[self nodeForSegmentType:VLCLibraryMusicSegment]];
+    } else if (segmentType >= VLCLibraryBrowseSegment &&
+               segmentType <= VLCLibraryBrowseBookmarkedLocationSubSegment) {
+        [self.outlineView expandItem:[self nodeForSegmentType:VLCLibraryBrowseSegment]];
     }
 
-    [self.outlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:segmentType]
+    NSTreeNode * const targetNode = [self nodeForSegmentType:segmentType];
+    const NSInteger segmentIndex = [self.outlineView rowForItem:targetNode];
+    [self.outlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:segmentIndex]
                   byExtendingSelection:NO];
 }
 
@@ -103,18 +166,33 @@ static NSString * const VLCLibrarySegmentCellIdentifier = @"VLCLibrarySegmentCel
     if (proposedSelectionIndexes.count == 0 || proposedSelectionIndexes.firstIndex != VLCLibraryMusicSegment) {
         return proposedSelectionIndexes;
     } else {
-        NSTreeNode * const itemNode = (NSTreeNode *)[_outlineView itemAtRow:VLCLibraryMusicSegment];
-        [self.outlineView expandItem:itemNode];
-        return [NSIndexSet indexSetWithIndex:VLCLibraryArtistsMusicSubSegment];
+        [self.outlineView expandItem:[self nodeForSegmentType:VLCLibraryMusicSegment]];
+        NSTreeNode * const artistsNode = [self nodeForSegmentType:VLCLibraryArtistsMusicSubSegment];
+        const NSInteger artistsIndex = [self.outlineView rowForItem:artistsNode];
+        return [NSIndexSet indexSetWithIndex:artistsIndex];
     }
 }
 
 - (void)outlineViewSelectionDidChange:(NSNotification *)notification
 {
+    if (self.ignoreSegmentSelectionChanges) {
+        return;
+    }
+    
     NSTreeNode * const node = (NSTreeNode *)[_outlineView itemAtRow:_outlineView.selectedRow];
     NSParameterAssert(node != nil);
     VLCLibrarySegment * const segment = (VLCLibrarySegment *)node.representedObject;
-    _libraryWindow.librarySegmentType = segment.segmentType;
+    NSObject * const representedObject = segment.representedObject;
+    NSParameterAssert(representedObject != nil);
+
+    if ([representedObject isKindOfClass:NSNumber.class]) {
+        self.libraryWindow.librarySegmentType = segment.segmentType;
+    } else if ([representedObject isKindOfClass:VLCLibrarySegmentBookmarkedLocation.class]) {
+        VLCLibrarySegmentBookmarkedLocation * const bookmarkedLocation =
+            (VLCLibrarySegmentBookmarkedLocation *)representedObject;
+        self.libraryWindow.librarySegmentType = bookmarkedLocation.segmentType;
+        [self.libraryWindow goToLocalFolderMrl:bookmarkedLocation.mrl];
+    }
 }
 
 @end


=====================================
modules/gui/macosx/library/VLCLibraryWindowToolbarDelegate.m
=====================================
@@ -169,6 +169,7 @@ NSString * const VLCLibraryWindowTrackingSeparatorToolbarItemIdentifier =
             break;
         case VLCLibraryBrowseSegment:
         case VLCLibraryStreamsSegment:
+        case VLCLibraryBrowseBookmarkedLocationSubSegment:
             [self setForwardsBackwardsToolbarItemsVisible:YES];
             [self setSortOrderToolbarItemVisible:NO];
             [self setLibrarySearchToolbarItemVisible:NO];


=====================================
modules/gui/macosx/library/media-source/VLCLibraryMediaSourceViewController.h
=====================================
@@ -51,6 +51,7 @@ NS_ASSUME_NONNULL_BEGIN
 
 - (void)presentBrowseView;
 - (void)presentStreamsView;
+- (void)presentLocalFolderMrl:(NSString *)mrl;
 
 @end
 


=====================================
modules/gui/macosx/library/media-source/VLCLibraryMediaSourceViewController.m
=====================================
@@ -190,4 +190,10 @@
     [_baseDataSource reloadViews];
 }
 
+- (void)presentLocalFolderMrl:(NSString *)mrl
+{
+    [self presentBrowseView];
+    [self.baseDataSource presentLocalFolderMrl:mrl];
+}
+
 @end


=====================================
modules/gui/macosx/library/media-source/VLCMediaSource.h
=====================================
@@ -41,6 +41,8 @@ extern NSString *VLCMediaSourcePreparsingEnded;
                   andLibVLCInstance:(libvlc_int_t *)p_libvlcInstance
                         forCategory:(enum services_discovery_category_e)category;
 - (instancetype)initMyFoldersMediaSourceWithLibVLCInstance:(libvlc_int_t *)p_libvlcInstance;
+- (instancetype)initWithLocalFolderMrl:(NSString *)mrl
+                     andLibVLCInstance:(libvlc_int_t *)p_libvlcInstance;
 
 - (void)preparseInputNodeWithinTree:(VLCInputNode *)inputNode;
 - (void)clearChildNodesForNode:(input_item_node_t*)inputNode;


=====================================
modules/gui/macosx/library/media-source/VLCMediaSource.m
=====================================
@@ -215,6 +215,51 @@ static const char *const myFoldersDescription = "My Folders";
     return self;
 }
 
+- (instancetype)initWithLocalFolderMrl:(NSString *)mrl
+                     andLibVLCInstance:(libvlc_int_t *)p_libvlcInstance
+{
+    self = [super init];
+    if (self) {
+        _p_libvlcInstance = p_libvlcInstance;
+
+         _p_mediaSource = malloc(sizeof(vlc_media_source_t));
+        if (!_p_mediaSource) {
+            return self;
+        }
+
+        _p_mediaSource->description = myFoldersDescription;
+        _p_mediaSource->tree = calloc(1, sizeof(vlc_media_tree_t));
+
+        if (_p_mediaSource->tree == NULL) {
+            free(_p_mediaSource);
+            _p_mediaSource = NULL;
+            return self;
+        }
+
+        _category = SD_CAT_MYCOMPUTER;
+
+        NSFileManager * const fileManager = NSFileManager.defaultManager;
+        NSURL * const directoryUrl = [NSURL URLWithString:mrl];
+        BOOL mrlTargetIsDirectory = NO;
+        const BOOL mrlTargetExists = [fileManager fileExistsAtPath:directoryUrl.path
+                                                       isDirectory:&mrlTargetIsDirectory];
+        if (!mrlTargetExists || !mrlTargetIsDirectory) {
+            return nil;
+        }
+
+        const char * const directoryPath = mrl.UTF8String;
+        const char * const directoryDesc = mrl.lastPathComponent.UTF8String;
+        input_item_t * const directoryItem = input_item_NewExt(directoryPath,
+                                                               directoryDesc,
+                                                               0,
+                                                               ITEM_TYPE_DIRECTORY,
+                                                               ITEM_LOCAL);
+        input_item_node_t * const directoryNode = input_item_node_Create(directoryItem);
+        _p_mediaSource->tree->root = *directoryNode;
+    }
+    return self;
+}
+
 - (void)dealloc
 {
     if (_p_mediaSource != NULL) {


=====================================
modules/gui/macosx/library/media-source/VLCMediaSourceBaseDataSource.h
=====================================
@@ -55,6 +55,8 @@ extern NSString * const VLCMediaSourceBaseDataSourceNodeChanged;
 - (void)homeButtonAction:(id)sender;
 - (void)pathControlAction:(id)sender;
 
+- (void)presentLocalFolderMrl:(NSString *)mrl;
+
 @end
 
 NS_ASSUME_NONNULL_END


=====================================
modules/gui/macosx/library/media-source/VLCMediaSourceBaseDataSource.m
=====================================
@@ -441,7 +441,8 @@ referenceSizeForHeaderInSection:(NSInteger)section
 
     if (_mediaSourceMode == VLCMediaSourceModeLAN) {
         VLCInputNode * const node = childDataSource.nodeToDisplay;
-        VLCInputNodePathControlItem * const nodePathItem = [[VLCInputNodePathControlItem alloc] initWithInputNode:node];
+        VLCInputNodePathControlItem * const nodePathItem = 
+            [[VLCInputNodePathControlItem alloc] initWithInputNode:node];
 
         [self.pathControl appendInputNodePathControlItem:nodePathItem];
     }
@@ -578,4 +579,17 @@ referenceSizeForHeaderInSection:(NSInteger)section
                                                       object:self];
 }
 
+- (void)presentLocalFolderMrl:(NSString *)mrl
+{
+    libvlc_int_t * const p_libvlcInstance = vlc_object_instance(getIntf());
+    VLCMediaSource * const mediaSource =
+        [[VLCMediaSource alloc] initWithLocalFolderMrl:mrl andLibVLCInstance:p_libvlcInstance];
+    if (mediaSource == nil) {
+        NSLog(@"Could not create valid media source for mrl: %@", mrl);
+        return;
+    }
+    [self configureChildDataSourceWithNode:mediaSource.rootNode andMediaSource:mediaSource];
+    [self reloadData];
+}
+
 @end



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/c6826ae20f58e39e3e980db2b887a7fae0592774...6909294e00ea5a046e0dd831f7b9819bab054ea7

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/c6826ae20f58e39e3e980db2b887a7fae0592774...6909294e00ea5a046e0dd831f7b9819bab054ea7
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance


More information about the vlc-commits mailing list