[vlc-commits] [Git][videolan/vlc][master] 15 commits: macosx: Replace normal video collection view with prototype cell-based video view

Jean-Baptiste Kempf (@jbk) gitlab at videolan.org
Thu Dec 1 22:38:41 UTC 2022



Jean-Baptiste Kempf pushed to branch master at VideoLAN / VLC


Commits:
8815e272 by Claudio Cambra at 2022-12-01T22:24:06+00:00
macosx: Replace normal video collection view with prototype cell-based video view

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

- - - - -
b7bdc155 by Claudio Cambra at 2022-12-01T22:24:06+00:00
macosx: Add VLCLibraryVideoCollectionViewGroupDescriptor to present collection view cell for different video groups, show Recents and Library

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

- - - - -
bf68e1e7 by Claudio Cambra at 2022-12-01T22:24:06+00:00
macosx: Use VLCSubScrollViews in the collection view cells to improve scroll

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

- - - - -
9f386220 by Claudio Cambra at 2022-12-01T22:24:06+00:00
macosx: Cache generated video library collection view table view cells instead of generating each time it is required for one to be displayed

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

- - - - -
72b2bbc9 by Claudio Cambra at 2022-12-01T22:24:06+00:00
macosx: Adjust rowheight of collection view table view cells to desired heights (short for horizontal recents, uncompressed for normal library)

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

- - - - -
ce6e055c by Claudio Cambra at 2022-12-01T22:24:06+00:00
macosx: Remove vertical scrollbars from the collection view table view cells

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

- - - - -
4db7ba91 by Claudio Cambra at 2022-12-01T22:24:06+00:00
macosx: Add inter-cell spacing between colelction view cells in video collection views table view

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

- - - - -
915c2ba9 by Claudio Cambra at 2022-12-01T22:24:06+00:00
macosx: Disable selection of collection view table view cells in video library grid view

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

- - - - -
da0e4bd5 by Claudio Cambra at 2022-12-01T22:24:06+00:00
macosx: Reintroduce supplementary views into the table cell collection views

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

- - - - -
b8762fce by Claudio Cambra at 2022-12-01T22:24:06+00:00
macosx: Extract new video library classes into independent files, organize video library files in video-library folder

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

- - - - -
2855bd0c by Claudio Cambra at 2022-12-01T22:24:06+00:00
macosx: Remove now unused collection view components from VLCVideoDataSource, rename it to VLCVideoTableViewDataSource

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

- - - - -
5a8f295f by Claudio Cambra at 2022-12-01T22:24:06+00:00
macosx: Unify use of video group enums, rename group descriptor to be view agnostic

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

- - - - -
6174bee6 by Claudio Cambra at 2022-12-01T22:24:06+00:00
macosx: Fix video library viles in POTFILES.in

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

- - - - -
5f9a5789 by Claudio Cambra at 2022-12-01T22:24:06+00:00
macosx: Use NSStackView as base for scrollable collection views view instead of NSTableView

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

- - - - -
57a72ded by Claudio Cambra at 2022-12-01T22:24:06+00:00
macosx: Give vide library collection views matching insets and spacing with other collection views in library

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

- - - - -


20 changed files:

- extras/package/macosx/VLC.xcodeproj/project.pbxproj
- modules/gui/macosx/Makefile.am
- modules/gui/macosx/UI/VLCLibraryWindow.xib
- modules/gui/macosx/library/VLCLibraryCollectionViewFlowLayout.m
- modules/gui/macosx/library/VLCLibraryTableCellView.m
- modules/gui/macosx/library/VLCLibraryWindow.h
- modules/gui/macosx/library/VLCLibraryWindow.m
- + modules/gui/macosx/library/video-library/VLCLibraryVideoCollectionViewContainerView.h
- + modules/gui/macosx/library/video-library/VLCLibraryVideoCollectionViewContainerView.m
- + modules/gui/macosx/library/video-library/VLCLibraryVideoCollectionViewContainerViewDataSource.h
- modules/gui/macosx/library/VLCLibraryVideoDataSource.m → modules/gui/macosx/library/video-library/VLCLibraryVideoCollectionViewContainerViewDataSource.m
- + modules/gui/macosx/library/video-library/VLCLibraryVideoCollectionViewsStackViewController.h
- + modules/gui/macosx/library/video-library/VLCLibraryVideoCollectionViewsStackViewController.m
- + modules/gui/macosx/library/video-library/VLCLibraryVideoGroupDescriptor.h
- + modules/gui/macosx/library/video-library/VLCLibraryVideoGroupDescriptor.m
- modules/gui/macosx/library/VLCLibraryVideoDataSource.h → modules/gui/macosx/library/video-library/VLCLibraryVideoTableViewDataSource.h
- + modules/gui/macosx/library/video-library/VLCLibraryVideoTableViewDataSource.m
- modules/gui/macosx/views/VLCSubScrollView.h
- modules/gui/macosx/views/VLCSubScrollView.m
- po/POTFILES.in


Changes:

=====================================
extras/package/macosx/VLC.xcodeproj/project.pbxproj
=====================================
@@ -77,6 +77,9 @@
 		1CCC89052078A3D500E5626F /* TextfieldPanel.xib in Sources */ = {isa = PBXBuildFile; fileRef = 6B8224151E4D2A9000833BE1 /* TextfieldPanel.xib */; };
 		1CCC89062078A3D500E5626F /* TimeSelectionPanel.xib in Sources */ = {isa = PBXBuildFile; fileRef = 6B8224161E4D2A9000833BE1 /* TimeSelectionPanel.xib */; };
 		1CFE8D591EA0D42A00E94451 /* VLCErrorWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1CFE8D581EA0D42A00E94451 /* VLCErrorWindowController.m */; };
+		5325C56A292D59FB00B2B63A /* VLCLibraryVideoCollectionViewContainerViewDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 5325C569292D59FB00B2B63A /* VLCLibraryVideoCollectionViewContainerViewDataSource.m */; };
+		5325C56D292D5CEB00B2B63A /* VLCLibraryVideoGroupDescriptor.m in Sources */ = {isa = PBXBuildFile; fileRef = 5325C56C292D5CEB00B2B63A /* VLCLibraryVideoGroupDescriptor.m */; };
+		5325C570292D5E8F00B2B63A /* VLCLibraryVideoCollectionViewContainerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5325C56F292D5E8F00B2B63A /* VLCLibraryVideoCollectionViewContainerView.m */; };
 		536283F0291146BC00640C15 /* VLCLibraryTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 536283DE291146BC00640C15 /* VLCLibraryTableView.m */; };
 		536283F1291146BC00640C15 /* VLCLibraryAlbumTracksDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 536283DF291146BC00640C15 /* VLCLibraryAlbumTracksDataSource.m */; };
 		536283F2291146BC00640C15 /* VLCLibraryCollectionViewAlbumSupplementaryDetailView.m in Sources */ = {isa = PBXBuildFile; fileRef = 536283E1291146BC00640C15 /* VLCLibraryCollectionViewAlbumSupplementaryDetailView.m */; };
@@ -89,6 +92,7 @@
 		536283F9291146BC00640C15 /* VLCLibraryCollectionViewFlowLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 536283EE291146BC00640C15 /* VLCLibraryCollectionViewFlowLayout.m */; };
 		53628402291147C500640C15 /* VLCBasicView.m in Sources */ = {isa = PBXBuildFile; fileRef = 536283FF291147C500640C15 /* VLCBasicView.m */; };
 		53628403291147C500640C15 /* VLCSubScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = 53628400291147C500640C15 /* VLCSubScrollView.m */; };
+		53E464782926EC0C008AE636 /* VLCLibraryVideoCollectionViewsStackViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 53E464762926EC0C008AE636 /* VLCLibraryVideoCollectionViewsStackViewController.m */; };
 		6B0292E61F43256300A50082 /* VLCBottomBarView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B0292E51F43256300A50082 /* VLCBottomBarView.m */; };
 		6B0AB0F01F1AC8B3003A1B4E /* VLCSlider.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B0AB0ED1F1AC8B3003A1B4E /* VLCSlider.m */; };
 		6B0AB0F11F1AC8B3003A1B4E /* VLCSliderCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B0AB0EF1F1AC8B3003A1B4E /* VLCSliderCell.m */; };
@@ -181,7 +185,7 @@
 		7DF0994F23E71E76007CA6EE /* NSMenu+VLCAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DF0994E23E71E76007CA6EE /* NSMenu+VLCAdditions.m */; };
 		7DFBDCA82269E77500B700A5 /* VLCLibraryController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DFBDCA72269E77500B700A5 /* VLCLibraryController.m */; };
 		7DFBDCAB2269E77F00B700A5 /* VLCLibraryModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DFBDCAA2269E77F00B700A5 /* VLCLibraryModel.m */; };
-		7DFBDCAE2269ED0C00B700A5 /* VLCLibraryVideoDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DFBDCAD2269ED0C00B700A5 /* VLCLibraryVideoDataSource.m */; };
+		7DFBDCAE2269ED0C00B700A5 /* VLCLibraryVideoTableViewDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DFBDCAD2269ED0C00B700A5 /* VLCLibraryVideoTableViewDataSource.m */; };
 		7DFBDCB1226A518400B700A5 /* VLCLibraryMenuController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DFBDCB0226A518400B700A5 /* VLCLibraryMenuController.m */; };
 		7DFBDCB4226CD00900B700A5 /* VLCLibraryDataTypes.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DFBDCB3226CD00900B700A5 /* VLCLibraryDataTypes.m */; };
 		7DFBDCB7226CDFD600B700A5 /* VLCImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DFBDCB6226CDFD600B700A5 /* VLCImageView.m */; };
@@ -228,6 +232,12 @@
 		1CFE8D561EA0D3D300E94451 /* ErrorPanel.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ErrorPanel.xib; sourceTree = "<group>"; };
 		1CFE8D571EA0D42A00E94451 /* VLCErrorWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VLCErrorWindowController.h; sourceTree = "<group>"; };
 		1CFE8D581EA0D42A00E94451 /* VLCErrorWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VLCErrorWindowController.m; sourceTree = "<group>"; };
+		5325C568292D59FB00B2B63A /* VLCLibraryVideoCollectionViewContainerViewDataSource.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VLCLibraryVideoCollectionViewContainerViewDataSource.h; sourceTree = "<group>"; };
+		5325C569292D59FB00B2B63A /* VLCLibraryVideoCollectionViewContainerViewDataSource.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VLCLibraryVideoCollectionViewContainerViewDataSource.m; sourceTree = "<group>"; };
+		5325C56B292D5CEB00B2B63A /* VLCLibraryVideoGroupDescriptor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VLCLibraryVideoGroupDescriptor.h; sourceTree = "<group>"; };
+		5325C56C292D5CEB00B2B63A /* VLCLibraryVideoGroupDescriptor.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VLCLibraryVideoGroupDescriptor.m; sourceTree = "<group>"; };
+		5325C56E292D5E8F00B2B63A /* VLCLibraryVideoCollectionViewContainerView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VLCLibraryVideoCollectionViewContainerView.h; sourceTree = "<group>"; };
+		5325C56F292D5E8F00B2B63A /* VLCLibraryVideoCollectionViewContainerView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VLCLibraryVideoCollectionViewContainerView.m; sourceTree = "<group>"; };
 		536283DC291146BC00640C15 /* VLCLibraryAlbumTracksDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VLCLibraryAlbumTracksDataSource.h; sourceTree = "<group>"; };
 		536283DD291146BC00640C15 /* VLCLibrarySongTableCellView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VLCLibrarySongTableCellView.h; sourceTree = "<group>"; };
 		536283DE291146BC00640C15 /* VLCLibraryTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VLCLibraryTableView.m; sourceTree = "<group>"; };
@@ -256,6 +266,8 @@
 		536283FF291147C500640C15 /* VLCBasicView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VLCBasicView.m; sourceTree = "<group>"; };
 		53628400291147C500640C15 /* VLCSubScrollView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VLCSubScrollView.m; sourceTree = "<group>"; };
 		53628401291147C500640C15 /* VLCSubScrollView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VLCSubScrollView.h; sourceTree = "<group>"; };
+		53E464762926EC0C008AE636 /* VLCLibraryVideoCollectionViewsStackViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VLCLibraryVideoCollectionViewsStackViewController.m; sourceTree = "<group>"; };
+		53E464772926EC0C008AE636 /* VLCLibraryVideoCollectionViewsStackViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VLCLibraryVideoCollectionViewsStackViewController.h; sourceTree = "<group>"; };
 		5CCED71014C0D4A90057F8D1 /* VLCExtensionsDialogProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VLCExtensionsDialogProvider.h; sourceTree = "<group>"; };
 		5CCED71114C0D4A90057F8D1 /* VLCExtensionsDialogProvider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VLCExtensionsDialogProvider.m; sourceTree = "<group>"; };
 		5CCED71214C0D4A90057F8D1 /* VLCExtensionsManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VLCExtensionsManager.h; sourceTree = "<group>"; };
@@ -639,8 +651,8 @@
 		7DFBDCA72269E77500B700A5 /* VLCLibraryController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VLCLibraryController.m; sourceTree = "<group>"; };
 		7DFBDCA92269E77F00B700A5 /* VLCLibraryModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VLCLibraryModel.h; sourceTree = "<group>"; };
 		7DFBDCAA2269E77F00B700A5 /* VLCLibraryModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VLCLibraryModel.m; sourceTree = "<group>"; };
-		7DFBDCAC2269ED0C00B700A5 /* VLCLibraryVideoDataSource.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VLCLibraryVideoDataSource.h; sourceTree = "<group>"; };
-		7DFBDCAD2269ED0C00B700A5 /* VLCLibraryVideoDataSource.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VLCLibraryVideoDataSource.m; sourceTree = "<group>"; };
+		7DFBDCAC2269ED0C00B700A5 /* VLCLibraryVideoTableViewDataSource.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VLCLibraryVideoTableViewDataSource.h; sourceTree = "<group>"; };
+		7DFBDCAD2269ED0C00B700A5 /* VLCLibraryVideoTableViewDataSource.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VLCLibraryVideoTableViewDataSource.m; sourceTree = "<group>"; };
 		7DFBDCAF226A518400B700A5 /* VLCLibraryMenuController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VLCLibraryMenuController.h; sourceTree = "<group>"; };
 		7DFBDCB0226A518400B700A5 /* VLCLibraryMenuController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VLCLibraryMenuController.m; sourceTree = "<group>"; };
 		7DFBDCB2226CD00900B700A5 /* VLCLibraryDataTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VLCLibraryDataTypes.h; sourceTree = "<group>"; };
@@ -1085,6 +1097,7 @@
 		1C1ED5132204B0CB00811EC0 /* library */ = {
 			isa = PBXGroup;
 			children = (
+				5325C567292D556800B2B63A /* video-library */,
 				7DFBDCBF226DC16200B700A5 /* VLCInputItem.h */,
 				7DFBDCC0226DC16200B700A5 /* VLCInputItem.m */,
 				7DE82E7722843781002D341A /* VLCLibraryAlbumTableCellView.h */,
@@ -1131,8 +1144,6 @@
 				7DE2F0462282D5D10040DD0A /* VLCLibraryTableCellView.m */,
 				536283E0291146BC00640C15 /* VLCLibraryTableView.h */,
 				536283DE291146BC00640C15 /* VLCLibraryTableView.m */,
-				7DFBDCAC2269ED0C00B700A5 /* VLCLibraryVideoDataSource.h */,
-				7DFBDCAD2269ED0C00B700A5 /* VLCLibraryVideoDataSource.m */,
 				7D713D302201AE350042BEB7 /* VLCLibraryWindow.h */,
 				7D713D312201AE350042BEB7 /* VLCLibraryWindow.m */,
 			);
@@ -1262,6 +1273,23 @@
 			path = renderers;
 			sourceTree = "<group>";
 		};
+		5325C567292D556800B2B63A /* video-library */ = {
+			isa = PBXGroup;
+			children = (
+				5325C56B292D5CEB00B2B63A /* VLCLibraryVideoGroupDescriptor.h */,
+				5325C56C292D5CEB00B2B63A /* VLCLibraryVideoGroupDescriptor.m */,
+				53E464772926EC0C008AE636 /* VLCLibraryVideoCollectionViewsStackViewController.h */,
+				53E464762926EC0C008AE636 /* VLCLibraryVideoCollectionViewsStackViewController.m */,
+				5325C56E292D5E8F00B2B63A /* VLCLibraryVideoCollectionViewContainerView.h */,
+				5325C56F292D5E8F00B2B63A /* VLCLibraryVideoCollectionViewContainerView.m */,
+				5325C568292D59FB00B2B63A /* VLCLibraryVideoCollectionViewContainerViewDataSource.h */,
+				5325C569292D59FB00B2B63A /* VLCLibraryVideoCollectionViewContainerViewDataSource.m */,
+				7DFBDCAC2269ED0C00B700A5 /* VLCLibraryVideoTableViewDataSource.h */,
+				7DFBDCAD2269ED0C00B700A5 /* VLCLibraryVideoTableViewDataSource.m */,
+			);
+			path = "video-library";
+			sourceTree = "<group>";
+		};
 		6B8224481E4D2B0500833BE1 /* Template Images */ = {
 			isa = PBXGroup;
 			children = (
@@ -1871,9 +1899,11 @@
 				1C3113C71E508C6900D4DD76 /* VLCOpenWindowController.m in Sources */,
 				7D0F64062202047900FDB91F /* VLCLibraryCollectionViewItem.m in Sources */,
 				7D713D322201AE350042BEB7 /* VLCLibraryWindow.m in Sources */,
+				53E464782926EC0C008AE636 /* VLCLibraryVideoCollectionViewsStackViewController.m in Sources */,
 				7D22A8F422BC14F80063ECD2 /* VLCLibrarySortingMenuController.m in Sources */,
 				1C3113C91E508C6900D4DD76 /* VLCOutput.m in Sources */,
 				1C1C62011F8260A90052DD4F /* VLCWrappableTextField.m in Sources */,
+				5325C570292D5E8F00B2B63A /* VLCLibraryVideoCollectionViewContainerView.m in Sources */,
 				6BBB05DA1EEFEA29003A1019 /* VLCHUDOutlineView.m in Sources */,
 				7D445D842202524D00263D34 /* VLCPlaylistItem.m in Sources */,
 				1C3113CF1E508C6900D4DD76 /* prefs_widgets.m in Sources */,
@@ -1884,7 +1914,7 @@
 				7DFBDCB1226A518400B700A5 /* VLCLibraryMenuController.m in Sources */,
 				536283F8291146BC00640C15 /* VLCLibrarySongTableCellView.m in Sources */,
 				1C3113D51E508C6900D4DD76 /* VLCTextfieldPanelController.m in Sources */,
-				7DFBDCAE2269ED0C00B700A5 /* VLCLibraryVideoDataSource.m in Sources */,
+				7DFBDCAE2269ED0C00B700A5 /* VLCLibraryVideoTableViewDataSource.m in Sources */,
 				53628403291147C500640C15 /* VLCSubScrollView.m in Sources */,
 				1C3113D71E508C6900D4DD76 /* VLCPopupPanelController.m in Sources */,
 				7DF0994F23E71E76007CA6EE /* NSMenu+VLCAdditions.m in Sources */,
@@ -1901,6 +1931,7 @@
 				6B6FFF701EF9EC350001CEB1 /* CompatibilityFixes.m in Sources */,
 				7D1BF28A22A153E20027C50F /* VLCRoundedCornerTextField.m in Sources */,
 				7DFBDCB4226CD00900B700A5 /* VLCLibraryDataTypes.m in Sources */,
+				5325C56A292D59FB00B2B63A /* VLCLibraryVideoCollectionViewContainerViewDataSource.m in Sources */,
 				1C3113DF1E508C6900D4DD76 /* VLCVideoEffectsWindowController.m in Sources */,
 				1C3113E11E508C6900D4DD76 /* VLCVoutView.m in Sources */,
 				1C3113E51E508C6900D4DD76 /* VLCInformationWindowController.m in Sources */,
@@ -1908,6 +1939,7 @@
 				7DB40D2A20CBCEB500F63173 /* VLCMainMenu.m in Sources */,
 				1C3113E91E508C6900D4DD76 /* VLCScrollingClipView.m in Sources */,
 				7DB40D2D20CBCEC200F63173 /* VLCStatusBarIcon.m in Sources */,
+				5325C56D292D5CEB00B2B63A /* VLCLibraryVideoGroupDescriptor.m in Sources */,
 				1C3113ED1E508C6900D4DD76 /* VLCTimeSelectionPanelController.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;


=====================================
modules/gui/macosx/Makefile.am
=====================================
@@ -102,10 +102,18 @@ libmacosx_plugin_la_SOURCES = \
 	gui/macosx/library/VLCLibraryTableView.m \
 	gui/macosx/library/VLCLibraryTableCellView.h \
 	gui/macosx/library/VLCLibraryTableCellView.m \
-	gui/macosx/library/VLCLibraryVideoDataSource.h \
-	gui/macosx/library/VLCLibraryVideoDataSource.m \
 	gui/macosx/library/VLCLibraryWindow.h \
 	gui/macosx/library/VLCLibraryWindow.m \
+	gui/macosx/library/video-library/VLCLibraryVideoCollectionViewsStackViewController.h \
+	gui/macosx/library/video-library/VLCLibraryVideoCollectionViewsStackViewController.m \
+	gui/macosx/library/video-library/VLCLibraryVideoCollectionViewContainerView.h \
+	gui/macosx/library/video-library/VLCLibraryVideoCollectionViewContainerView.m \
+	gui/macosx/library/video-library/VLCLibraryVideoCollectionViewContainerViewDataSource.h \
+	gui/macosx/library/video-library/VLCLibraryVideoCollectionViewContainerViewDataSource.m \
+	gui/macosx/library/video-library/VLCLibraryVideoGroupDescriptor.h \
+	gui/macosx/library/video-library/VLCLibraryVideoGroupDescriptor.m \
+	gui/macosx/library/video-library/VLCLibraryVideoTableViewDataSource.h \
+	gui/macosx/library/video-library/VLCLibraryVideoTableViewDataSource.m \
 	gui/macosx/main/CompatibilityFixes.h \
 	gui/macosx/main/CompatibilityFixes.m \
 	gui/macosx/main/VLCApplication.h \


=====================================
modules/gui/macosx/UI/VLCLibraryWindow.xib
=====================================
@@ -25,18 +25,18 @@
                 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                 <subviews>
                     <splitView autosaveName="librarywindowsplitview" dividerStyle="thin" vertical="YES" translatesAutoresizingMaskIntoConstraints="NO" id="u8g-jy-S4e">
-                        <rect key="frame" x="0.0" y="81" width="896" height="134"/>
+                        <rect key="frame" x="0.0" y="81" width="896" height="138"/>
                         <subviews>
                             <customView misplaced="YES" id="iSp-bV-w6B" customClass="VLCBasicView">
-                                <rect key="frame" x="0.0" y="0.0" width="598" height="134"/>
+                                <rect key="frame" x="0.0" y="0.0" width="598" height="138"/>
                                 <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                             </customView>
                             <customView misplaced="YES" id="dus-WQ-AmE">
-                                <rect key="frame" x="599" y="0.0" width="297" height="134"/>
+                                <rect key="frame" x="599" y="0.0" width="297" height="138"/>
                                 <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                                 <subviews>
                                     <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="TET-5r-zHx">
-                                        <rect key="frame" x="18" y="92" width="66" height="31"/>
+                                        <rect key="frame" x="18" y="102" width="66" height="31"/>
                                         <textFieldCell key="cell" lineBreakMode="clipping" title="Label" id="fo5-R8-TeO">
                                             <font key="font" textStyle="largeTitle" name=".SFNS-Regular"/>
                                             <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
@@ -44,7 +44,7 @@
                                         </textFieldCell>
                                     </textField>
                                     <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="mbV-My-cm7" customClass="VLCRoundedCornerTextField">
-                                        <rect key="frame" x="153" y="100" width="37" height="16"/>
+                                        <rect key="frame" x="153" y="110" width="37" height="16"/>
                                         <textFieldCell key="cell" lineBreakMode="clipping" title="Label" id="4hq-fU-NXW">
                                             <font key="font" metaFont="message"/>
                                             <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
@@ -52,12 +52,12 @@
                                         </textFieldCell>
                                     </textField>
                                     <box verticalHuggingPriority="750" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="qmL-Ar-cj1">
-                                        <rect key="frame" x="20" y="82" width="168" height="5"/>
+                                        <rect key="frame" x="20" y="92" width="168" height="5"/>
                                     </box>
                                     <scrollView borderType="none" autohidesScrollers="YES" horizontalLineScroll="19" horizontalPageScroll="10" verticalLineScroll="19" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Z7y-D0-11Q">
-                                        <rect key="frame" x="0.0" y="62" width="208" height="14"/>
+                                        <rect key="frame" x="0.0" y="68" width="208" height="18"/>
                                         <clipView key="contentView" drawsBackground="NO" copiesOnScroll="NO" id="Vdr-bg-tuS">
-                                            <rect key="frame" x="0.0" y="0.0" width="208" height="14"/>
+                                            <rect key="frame" x="0.0" y="0.0" width="208" height="18"/>
                                             <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                                             <subviews>
                                                 <tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" multipleSelection="NO" autosaveColumns="NO" rowSizeStyle="automatic" viewBased="YES" id="Fr1-af-8gb" customClass="VLCPlaylistTableView">
@@ -122,10 +122,10 @@
                                         </scroller>
                                     </scrollView>
                                     <box verticalHuggingPriority="750" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="nAW-KH-ipk">
-                                        <rect key="frame" x="20" y="51" width="168" height="5"/>
+                                        <rect key="frame" x="20" y="57" width="168" height="5"/>
                                     </box>
                                     <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="jg5-33-vH0">
-                                        <rect key="frame" x="20" y="14" width="24" height="24"/>
+                                        <rect key="frame" x="20" y="20" width="24" height="24"/>
                                         <buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="shuffleOn" imagePosition="only" alignment="center" imageScaling="proportionallyDown" inset="2" id="J31-h3-U4s">
                                             <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
                                             <font key="font" metaFont="system"/>
@@ -135,7 +135,7 @@
                                         </connections>
                                     </button>
                                     <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="8zF-Wo-H79">
-                                        <rect key="frame" x="64" y="14" width="24" height="24"/>
+                                        <rect key="frame" x="64" y="20" width="24" height="24"/>
                                         <buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="repeatOff" imagePosition="only" alignment="center" imageScaling="proportionallyDown" inset="2" id="ol2-xi-TEm">
                                             <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
                                             <font key="font" metaFont="system"/>
@@ -145,7 +145,7 @@
                                         </connections>
                                     </button>
                                     <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="cih-xp-HmY">
-                                        <rect key="frame" x="174" y="11" width="14.5" height="17"/>
+                                        <rect key="frame" x="173" y="17" width="15" height="17"/>
                                         <buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="trash" catalog="system" imagePosition="only" alignment="center" imageScaling="proportionallyDown" inset="2" id="OjM-W9-IrQ">
                                             <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
                                             <font key="font" metaFont="system"/>
@@ -155,10 +155,10 @@
                                         </connections>
                                     </button>
                                     <customView hidden="YES" translatesAutoresizingMaskIntoConstraints="NO" id="VFI-oW-dMZ" customClass="VLCDragDropView">
-                                        <rect key="frame" x="0.0" y="54" width="208" height="30"/>
+                                        <rect key="frame" x="0.0" y="60" width="208" height="34"/>
                                         <subviews>
                                             <box boxType="custom" borderType="line" borderWidth="0.0" cornerRadius="10" titlePosition="noTitle" translatesAutoresizingMaskIntoConstraints="NO" id="AXk-h7-dZ0">
-                                                <rect key="frame" x="37" y="-52" width="134" height="134"/>
+                                                <rect key="frame" x="37" y="-50" width="134" height="134"/>
                                                 <view key="contentView" id="NSp-cB-V4X">
                                                     <rect key="frame" x="0.0" y="0.0" width="134" height="134"/>
                                                     <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
@@ -166,7 +166,7 @@
                                                 <color key="borderColor" name="separatorColor" catalog="System" colorSpace="catalog"/>
                                             </box>
                                             <imageView translatesAutoresizingMaskIntoConstraints="NO" id="cTV-Wf-TfJ" customClass="VLCDropDisabledImageView">
-                                                <rect key="frame" x="48" y="-41" width="112" height="112"/>
+                                                <rect key="frame" x="48" y="-39" width="112" height="112"/>
                                                 <constraints>
                                                     <constraint firstAttribute="width" constant="112" id="IvG-i0-rbs"/>
                                                     <constraint firstAttribute="height" constant="112" id="dO8-Iv-pDk"/>
@@ -174,7 +174,7 @@
                                                 <imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="dropzone" id="sHO-XQ-hCU"/>
                                             </imageView>
                                             <button wantsLayer="YES" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="SWh-4E-Qtf">
-                                                <rect key="frame" x="44" y="-89" width="120" height="32"/>
+                                                <rect key="frame" x="44" y="-87" width="120" height="32"/>
                                                 <buttonCell key="cell" type="push" title="Open media..." bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="UUH-HF-Iqc">
                                                     <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
                                                     <font key="font" metaFont="system"/>
@@ -196,7 +196,7 @@
                                         </constraints>
                                     </customView>
                                     <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="244-FS-P3T">
-                                        <rect key="frame" x="148" y="14" width="16" height="10"/>
+                                        <rect key="frame" x="146" y="20" width="17" height="10"/>
                                         <buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="line.horizontal.3.decrease" catalog="system" imagePosition="only" alignment="center" imageScaling="proportionallyDown" inset="2" id="qDZ-84-3uy">
                                             <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
                                             <font key="font" metaFont="system"/>
@@ -725,8 +725,8 @@
                 <outlet property="shufflePlaylistButton" destination="jg5-33-vH0" id="FV2-36-3lG"/>
                 <outlet property="upNextLabel" destination="TET-5r-zHx" id="3oI-LK-NDP"/>
                 <outlet property="upNextSeparator" destination="qmL-Ar-cj1" id="GRX-ZE-2UG"/>
-                <outlet property="videoLibraryCollectionView" destination="B8x-e8-7zp" id="u1I-gn-IU1"/>
-                <outlet property="videoLibraryCollectionViewScrollView" destination="nXS-11-7iK" id="v1d-30-scr"/>
+                <outlet property="videoLibraryCollectionViewsStackView" destination="y8S-p5-jaq" id="c01-v1-eW3"/>
+                <outlet property="videoLibraryCollectionViewsStackViewScrollView" destination="GUe-Sd-j2l" id="scr-v1-eW3"/>
                 <outlet property="videoLibraryGroupSelectionTableView" destination="8M4-Y1-r6Z" id="5e1-v1-eW3"/>
                 <outlet property="videoLibraryGroupSelectionTableViewScrollView" destination="Z0p-XI-Rpc" id="s3l-Sc-Rv1"/>
                 <outlet property="videoLibraryGroupsTableView" destination="ceR-Vd-9ss" id="gr0-Up-5v1"/>
@@ -763,6 +763,42 @@
             <rect key="frame" x="0.0" y="0.0" width="869" height="808"/>
             <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
             <subviews>
+                <scrollView horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="GUe-Sd-j2l">
+                    <rect key="frame" x="0.0" y="0.0" width="869" height="808"/>
+                    <clipView key="contentView" id="mqU-ND-NId">
+                        <rect key="frame" x="1" y="1" width="852" height="806"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <view translatesAutoresizingMaskIntoConstraints="NO" id="fxG-zK-eLG">
+                                <rect key="frame" x="0.0" y="806" width="836" height="0.0"/>
+                                <subviews>
+                                    <stackView distribution="fill" orientation="vertical" alignment="leading" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="y8S-p5-jaq">
+                                        <rect key="frame" x="0.0" y="0.0" width="836" height="0.0"/>
+                                    </stackView>
+                                </subviews>
+                                <constraints>
+                                    <constraint firstAttribute="trailing" secondItem="y8S-p5-jaq" secondAttribute="trailing" id="Dko-7p-ZXb"/>
+                                    <constraint firstItem="y8S-p5-jaq" firstAttribute="top" secondItem="fxG-zK-eLG" secondAttribute="top" id="WV2-VH-ZU1"/>
+                                    <constraint firstAttribute="bottom" secondItem="y8S-p5-jaq" secondAttribute="bottom" id="lfA-09-bPW"/>
+                                    <constraint firstItem="y8S-p5-jaq" firstAttribute="leading" secondItem="fxG-zK-eLG" secondAttribute="leading" id="oYg-7c-PgU"/>
+                                </constraints>
+                            </view>
+                        </subviews>
+                        <constraints>
+                            <constraint firstItem="fxG-zK-eLG" firstAttribute="leading" secondItem="mqU-ND-NId" secondAttribute="leading" id="GbP-aj-zwg"/>
+                            <constraint firstAttribute="trailing" secondItem="fxG-zK-eLG" secondAttribute="trailing" constant="16" id="jxY-Zd-X2Y"/>
+                            <constraint firstItem="fxG-zK-eLG" firstAttribute="top" secondItem="mqU-ND-NId" secondAttribute="top" id="nHB-La-592"/>
+                        </constraints>
+                    </clipView>
+                    <scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="EKY-s7-5EI">
+                        <rect key="frame" x="-100" y="-100" width="852" height="15"/>
+                        <autoresizingMask key="autoresizingMask"/>
+                    </scroller>
+                    <scroller key="verticalScroller" wantsLayer="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="NO" id="hqo-ev-Oma">
+                        <rect key="frame" x="853" y="1" width="15" height="806"/>
+                        <autoresizingMask key="autoresizingMask"/>
+                    </scroller>
+                </scrollView>
                 <splitView dividerStyle="thin" vertical="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Lfx-Wq-a7c">
                     <rect key="frame" x="0.0" y="0.0" width="869" height="808"/>
                     <subviews>
@@ -889,43 +925,16 @@
                         <real value="250"/>
                     </holdingPriorities>
                 </splitView>
-                <scrollView wantsLayer="YES" borderType="none" autohidesScrollers="YES" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="nXS-11-7iK">
-                    <rect key="frame" x="0.0" y="0.0" width="869" height="808"/>
-                    <clipView key="contentView" copiesOnScroll="NO" id="OKa-dt-1yY">
-                        <rect key="frame" x="0.0" y="0.0" width="869" height="808"/>
-                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
-                        <subviews>
-                            <collectionView selectable="YES" id="B8x-e8-7zp">
-                                <rect key="frame" x="0.0" y="0.0" width="869" height="808"/>
-                                <autoresizingMask key="autoresizingMask" widthSizable="YES"/>
-                                <collectionViewFlowLayout key="collectionViewLayout" minimumInteritemSpacing="20" minimumLineSpacing="20" id="Rag-cM-k1g">
-                                    <size key="itemSize" width="256" height="214"/>
-                                    <edgeInsets key="sectionInset" left="20" right="20" top="20" bottom="20"/>
-                                </collectionViewFlowLayout>
-                                <color key="primaryBackgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
-                                <color key="secondaryBackgroundColor" name="controlAlternatingRowColor" catalog="System" colorSpace="catalog"/>
-                            </collectionView>
-                        </subviews>
-                    </clipView>
-                    <scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="7ik-B8-JYg">
-                        <rect key="frame" x="-100" y="-100" width="233" height="15"/>
-                        <autoresizingMask key="autoresizingMask"/>
-                    </scroller>
-                    <scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="NO" id="rUh-Qg-gUL">
-                        <rect key="frame" x="226" y="0.0" width="16" height="291"/>
-                        <autoresizingMask key="autoresizingMask"/>
-                    </scroller>
-                </scrollView>
             </subviews>
             <constraints>
-                <constraint firstItem="nXS-11-7iK" firstAttribute="top" secondItem="vak-Gp-ljo" secondAttribute="top" id="KNa-C4-CIY"/>
-                <constraint firstItem="nXS-11-7iK" firstAttribute="leading" secondItem="vak-Gp-ljo" secondAttribute="leading" id="LP8-Hf-WCx"/>
+                <constraint firstItem="GUe-Sd-j2l" firstAttribute="leading" secondItem="vak-Gp-ljo" secondAttribute="leading" id="6FZ-mu-ICw"/>
+                <constraint firstAttribute="trailing" secondItem="GUe-Sd-j2l" secondAttribute="trailing" id="EhR-kx-PFH"/>
                 <constraint firstItem="Lfx-Wq-a7c" firstAttribute="top" secondItem="vak-Gp-ljo" secondAttribute="top" id="SC1-l6-nTO"/>
+                <constraint firstAttribute="bottom" secondItem="GUe-Sd-j2l" secondAttribute="bottom" id="TD1-jC-Kd8"/>
+                <constraint firstItem="GUe-Sd-j2l" firstAttribute="top" secondItem="vak-Gp-ljo" secondAttribute="top" id="Uec-xQ-d9f"/>
                 <constraint firstItem="Lfx-Wq-a7c" firstAttribute="leading" secondItem="vak-Gp-ljo" secondAttribute="leading" id="aaz-JM-Edt"/>
-                <constraint firstAttribute="trailing" secondItem="nXS-11-7iK" secondAttribute="trailing" id="kmc-KU-iRY"/>
                 <constraint firstAttribute="bottom" secondItem="Lfx-Wq-a7c" secondAttribute="bottom" id="n0b-r7-3FH"/>
                 <constraint firstAttribute="trailing" secondItem="Lfx-Wq-a7c" secondAttribute="trailing" id="nCg-WG-I3Y"/>
-                <constraint firstAttribute="bottom" secondItem="nXS-11-7iK" secondAttribute="bottom" id="tpH-Q7-TH4"/>
             </constraints>
             <point key="canvasLocation" x="748.5" y="10"/>
         </customView>
@@ -1262,21 +1271,21 @@
         </customView>
     </objects>
     <resources>
-        <image name="NSHomeTemplate" width="24" height="21"/>
-        <image name="NSIconViewTemplate" width="19" height="18"/>
-        <image name="NSLeftFacingTriangleTemplate" width="12" height="17"/>
-        <image name="NSListViewTemplate" width="21" height="15"/>
-        <image name="NSRightFacingTriangleTemplate" width="12" height="17"/>
+        <image name="NSHomeTemplate" width="24" height="20"/>
+        <image name="NSIconViewTemplate" width="19" height="17"/>
+        <image name="NSLeftFacingTriangleTemplate" width="12" height="16"/>
+        <image name="NSListViewTemplate" width="21" height="14"/>
+        <image name="NSRightFacingTriangleTemplate" width="12" height="16"/>
         <image name="VLC" width="512" height="512"/>
         <image name="VLCBackwardTemplate" width="128" height="128"/>
         <image name="VLCForwardTemplate" width="128" height="128"/>
-        <image name="arrow.up.arrow.down" catalog="system" width="18" height="15"/>
+        <image name="arrow.up.arrow.down" catalog="system" width="19" height="15"/>
         <image name="dropzone" width="112" height="112"/>
         <image name="fullscreen-one-button" width="29" height="23"/>
         <image name="fullscreen-one-button-pressed" width="29" height="23"/>
         <image name="libraryPlay" width="64" height="64"/>
-        <image name="line.horizontal.3.decrease" catalog="system" width="16" height="10"/>
-        <image name="music.note.list" catalog="system" width="16" height="15"/>
+        <image name="line.horizontal.3.decrease" catalog="system" width="17" height="10"/>
+        <image name="music.note.list" catalog="system" width="17" height="15"/>
         <image name="repeatOff" width="24" height="24"/>
         <image name="shuffleOn" width="24" height="24"/>
         <image name="stop" width="29" height="23"/>


=====================================
modules/gui/macosx/library/VLCLibraryCollectionViewFlowLayout.m
=====================================
@@ -23,11 +23,12 @@
 #import "VLCLibraryCollectionViewFlowLayout.h"
 
 #import "VLCLibraryAudioDataSource.h"
-#import "VLCLibraryVideoDataSource.h"
 #import "VLCLibraryCollectionViewAlbumSupplementaryDetailView.h"
 #import "VLCLibraryCollectionViewAudioGroupSupplementaryDetailView.h"
 #import "VLCLibraryCollectionViewMediaItemSupplementaryDetailView.h"
 
+#import "library/video-library/VLCLibraryVideoCollectionViewContainerViewDataSource.h"
+
 #pragma mark - Private data
 static const NSUInteger kAnimationSteps = 32;
 static const NSUInteger kWrapAroundValue = (NSUInteger)-1;
@@ -216,8 +217,8 @@ static CVReturn detailViewAnimationCallback(CVDisplayLinkRef displayLink,
                 [layoutAttributesArray addObject:[self layoutAttributesForSupplementaryViewOfKind:VLCLibraryCollectionViewMediaItemSupplementaryDetailViewKind atIndexPath:self.selectedIndexPath]];
                 break;
         }
-    } else if([self.collectionView.dataSource isKindOfClass:[VLCLibraryVideoDataSource class]]) {
-        VLCLibraryVideoDataSource *videoDataSource = (VLCLibraryVideoDataSource *)self.collectionView.dataSource;
+    } else if([self.collectionView.dataSource isKindOfClass:[VLCLibraryVideoCollectionViewContainerViewDataSource class]]) {
+        VLCLibraryVideoCollectionViewContainerViewDataSource *videoDataSource = (VLCLibraryVideoCollectionViewContainerViewDataSource *)self.collectionView.dataSource;
         [layoutAttributesArray addObject:[self layoutAttributesForSupplementaryViewOfKind:VLCLibraryCollectionViewMediaItemSupplementaryDetailViewKind atIndexPath:self.selectedIndexPath]];
     }
     


=====================================
modules/gui/macosx/library/VLCLibraryTableCellView.m
=====================================
@@ -31,7 +31,7 @@
 #import "library/VLCLibraryController.h"
 #import "library/VLCLibraryDataTypes.h"
 #import "library/VLCInputItem.h"
-#import "library/VLCLibraryVideoDataSource.h"
+#import "library/video-library/VLCLibraryVideoGroupDescriptor.h"
 #import "playlist/VLCPlaylistController.h"
 
 @implementation VLCLibraryTableCellView
@@ -106,11 +106,11 @@
 - (void)setRepresentedVideoLibrarySection:(NSUInteger)section
 {
     NSString *sectionString = @"";
-    switch(section) {
-        case VLCVideoLibraryRecentsSection:
+    switch(section + 1) { // Group 0 is Invalid, so add one
+        case VLCLibraryVideoRecentsGroup:
             sectionString = _NS("Recents");
             break;
-        case VLCVideoLibraryLibrarySection:
+        case VLCLibraryVideoLibraryGroup:
             sectionString = _NS("Library");
             break;
         default:


=====================================
modules/gui/macosx/library/VLCLibraryWindow.h
=====================================
@@ -28,7 +28,8 @@ NS_ASSUME_NONNULL_BEGIN
 @class VLCRoundedCornerTextField;
 @class VLCLibraryNavigationStack;
 @class VLCLibraryAudioDataSource;
- at class VLCLibraryVideoDataSource;
+ at class VLCLibraryVideoCollectionViewsStackViewController;
+ at class VLCLibraryVideoTableViewDataSource;
 @class VLCLibraryGroupDataSource;
 @class VLCLibrarySortingMenuController;
 @class VLCMediaSourceBaseDataSource;
@@ -64,8 +65,8 @@ typedef NS_ENUM(NSUInteger, VLCViewModeSegment) {
 @property (readwrite, strong) IBOutlet NSView *playlistView;
 @property (readwrite, weak) IBOutlet NSView *videoLibraryView;
 @property (readwrite, weak) IBOutlet NSSplitView *videoLibrarySplitView;
- at property (readwrite, weak) IBOutlet NSScrollView *videoLibraryCollectionViewScrollView;
- at property (readwrite, weak) IBOutlet NSCollectionView *videoLibraryCollectionView;
+ at property (readwrite, weak) IBOutlet NSScrollView *videoLibraryCollectionViewsStackViewScrollView;
+ at property (readwrite, weak) IBOutlet NSStackView *videoLibraryCollectionViewsStackView;
 @property (readwrite, weak) IBOutlet NSScrollView *videoLibraryGroupSelectionTableViewScrollView;
 @property (readwrite, weak) IBOutlet NSTableView *videoLibraryGroupSelectionTableView;
 @property (readwrite, weak) IBOutlet NSScrollView *videoLibraryGroupsTableViewScrollView;
@@ -112,7 +113,8 @@ typedef NS_ENUM(NSUInteger, VLCViewModeSegment) {
 @property (readwrite) BOOL nonembedded;
 @property (readwrite) VLCLibraryNavigationStack *navigationStack;
 @property (readonly) VLCLibraryAudioDataSource *libraryAudioDataSource;
- at property (readonly) VLCLibraryVideoDataSource *libraryVideoDataSource;
+ at property (readonly) VLCLibraryVideoTableViewDataSource *libraryVideoTableViewDataSource;
+ at property (readonly) VLCLibraryVideoCollectionViewsStackViewController *libraryVideoCollectionViewsStackViewController;
 @property (readonly) VLCLibraryGroupDataSource *libraryAudioGroupDataSource;
 @property (readonly) VLCLibrarySortingMenuController *librarySortingMenuController;
 @property (readonly) VLCMediaSourceBaseDataSource *mediaSourceDataSource;


=====================================
modules/gui/macosx/library/VLCLibraryWindow.m
=====================================
@@ -35,7 +35,6 @@
 
 #import "library/VLCLibraryController.h"
 #import "library/VLCLibraryAudioDataSource.h"
-#import "library/VLCLibraryVideoDataSource.h"
 #import "library/VLCLibraryCollectionViewItem.h"
 #import "library/VLCLibraryModel.h"
 #import "library/VLCLibraryCollectionViewSupplementaryElementView.h"
@@ -43,6 +42,9 @@
 #import "library/VLCLibraryAlbumTableCellView.h"
 #import "library/VLCLibraryNavigationStack.h"
 
+#import "library/video-library/VLCLibraryVideoCollectionViewsStackViewController.h"
+#import "library/video-library/VLCLibraryVideoTableViewDataSource.h"
+
 #import "media-source/VLCMediaSourceBaseDataSource.h"
 
 #import "views/VLCCustomWindowButton.h"
@@ -282,14 +284,17 @@ static void addShadow(NSImageView *__unsafe_unretained imageView)
     [self updateViewCellDimensionsBasedOnSetting:nil];
     [_playlistTableView reloadData];
 
-    _libraryVideoDataSource = [[VLCLibraryVideoDataSource alloc] init];
-    _libraryVideoDataSource.libraryModel = mainInstance.libraryController.libraryModel;
-    _libraryVideoDataSource.libraryMediaCollectionView = _videoLibraryCollectionView;
-    _libraryVideoDataSource.groupsTableView = _videoLibraryGroupsTableView;
-    _libraryVideoDataSource.groupSelectionTableView = _videoLibraryGroupSelectionTableView;
+    _libraryVideoTableViewDataSource = [[VLCLibraryVideoTableViewDataSource alloc] init];
+    _libraryVideoTableViewDataSource.libraryModel = mainInstance.libraryController.libraryModel;
+    _libraryVideoTableViewDataSource.groupsTableView = _videoLibraryGroupsTableView;
+    _libraryVideoTableViewDataSource.groupSelectionTableView = _videoLibraryGroupSelectionTableView;
     _videoLibraryGroupsTableView.rowHeight = VLCLibraryWindowLargeRowHeight;
     _videoLibraryGroupSelectionTableView.rowHeight = VLCLibraryWindowLargeRowHeight;
-    [_libraryVideoDataSource setup];
+    [_libraryVideoTableViewDataSource setup];
+
+    _libraryVideoCollectionViewsStackViewController = [[VLCLibraryVideoCollectionViewsStackViewController alloc] init];
+    _libraryVideoCollectionViewsStackViewController.collectionsStackViewScrollView = _videoLibraryCollectionViewsStackViewScrollView;
+    _libraryVideoCollectionViewsStackViewController.collectionsStackView = _videoLibraryCollectionViewsStackView;
 
     _libraryAudioDataSource = [[VLCLibraryAudioDataSource alloc] init];
     _libraryAudioDataSource.libraryModel = mainInstance.libraryController.libraryModel;
@@ -374,9 +379,9 @@ static void addShadow(NSImageView *__unsafe_unretained imageView)
     _audioGroupSelectionTableViewScrollView.contentInsets = audioScrollViewInsets;
     _audioGroupSelectionTableViewScrollView.scrollerInsets = scrollerInsets;
     
-    _videoLibraryCollectionViewScrollView.automaticallyAdjustsContentInsets = NO;
-    _videoLibraryCollectionViewScrollView.contentInsets = defaultInsets;
-    _videoLibraryCollectionViewScrollView.scrollerInsets = scrollerInsets;
+    _videoLibraryCollectionViewsStackViewScrollView.automaticallyAdjustsContentInsets = NO;
+    _videoLibraryCollectionViewsStackViewScrollView.contentInsets = defaultInsets;
+    _videoLibraryCollectionViewsStackViewScrollView.scrollerInsets = scrollerInsets;
     
     _videoLibraryGroupsTableViewScrollView.automaticallyAdjustsContentInsets = NO;
     _videoLibraryGroupsTableViewScrollView.contentInsets = defaultInsets;
@@ -402,11 +407,10 @@ static void addShadow(NSImageView *__unsafe_unretained imageView)
     audioLibraryCollectionViewLayout.minimumInteritemSpacing = collectionItemSpacing;
     audioLibraryCollectionViewLayout.sectionInset = collectionViewSectionInset;
 
-    NSCollectionViewFlowLayout *videoLibraryCollectionViewLayout = _videoLibraryCollectionView.collectionViewLayout;
-    videoLibraryCollectionViewLayout.itemSize = CGSizeMake(214., 260.);
-    videoLibraryCollectionViewLayout.minimumLineSpacing = collectionItemSpacing;
-    videoLibraryCollectionViewLayout.minimumInteritemSpacing = collectionItemSpacing;
-    videoLibraryCollectionViewLayout.sectionInset = collectionViewSectionInset;
+    _libraryVideoCollectionViewsStackViewController.collectionViewItemSize = CGSizeMake(214., 260.);
+    _libraryVideoCollectionViewsStackViewController.collectionViewMinimumLineSpacing = collectionItemSpacing;
+    _libraryVideoCollectionViewsStackViewController.collectionViewMinimumInteritemSpacing = collectionItemSpacing;
+    _libraryVideoCollectionViewsStackViewController.collectionViewSectionInset = collectionViewSectionInset;
 
     NSCollectionViewFlowLayout *mediaSourceCollectionViewLayout = _mediaSourceCollectionView.collectionViewLayout;
     mediaSourceCollectionViewLayout.itemSize = CGSizeMake(214., 246.);
@@ -579,7 +583,7 @@ static void addShadow(NSImageView *__unsafe_unretained imageView)
         [subview removeFromSuperview];
     }
     
-    if (_libraryVideoDataSource.libraryModel.numberOfVideoMedia == 0) { // empty library
+    if (_libraryVideoTableViewDataSource.libraryModel.numberOfVideoMedia == 0) { // empty library
         for (NSLayoutConstraint *constraint in audioPlaceholderImageViewSizeConstraints) {
             constraint.active = NO;
         }
@@ -604,13 +608,13 @@ static void addShadow(NSImageView *__unsafe_unretained imageView)
         
         if (self.gridVsListSegmentedControl.selectedSegment == VLCGridViewModeSegment) {
             _videoLibrarySplitView.hidden = YES;
-            _videoLibraryCollectionViewScrollView.hidden = NO;
+            _videoLibraryCollectionViewsStackViewScrollView.hidden = NO;
+            [_libraryVideoCollectionViewsStackViewController reloadData];
         } else {
             _videoLibrarySplitView.hidden = NO;
-            _videoLibraryCollectionViewScrollView.hidden = YES;
+            _videoLibraryCollectionViewsStackViewScrollView.hidden = YES;
+            [_libraryVideoTableViewDataSource reloadData];
         }
-        
-        [_libraryVideoDataSource reloadData];
     }
     
     _librarySortButton.hidden = NO;
@@ -985,7 +989,11 @@ static void addShadow(NSImageView *__unsafe_unretained imageView)
 - (void)updateLibraryRepresentation:(NSNotification *)aNotification
 {
     if (_videoLibraryView.superview != nil) {
-        [_libraryVideoDataSource reloadData];
+        if (self.gridVsListSegmentedControl.selectedSegment == VLCGridViewModeSegment) {
+            [_libraryVideoCollectionViewsStackViewController reloadData];
+        } else {
+            [_libraryVideoTableViewDataSource reloadData];
+        }
     } else if (_audioLibraryView.superview != nil) {
         [_libraryAudioDataSource reloadAppearance];
     }


=====================================
modules/gui/macosx/library/video-library/VLCLibraryVideoCollectionViewContainerView.h
=====================================
@@ -0,0 +1,48 @@
+/*****************************************************************************
+ * VLCLibraryVideoCollectionViewContainerView.h: MacOS X interface module
+ *****************************************************************************
+ * Copyright (C) 2022 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>
+
+#import "library/video-library/VLCLibraryVideoGroupDescriptor.h"
+
+ at class VLCSubScrollView;
+ at class VLCLibraryCollectionViewFlowLayout;
+ at class VLCLibraryVideoCollectionViewGroupDescriptor;
+ at class VLCLibraryVideoCollectionViewContainerViewDataSource;
+
+NS_ASSUME_NONNULL_BEGIN
+
+ at interface VLCLibraryVideoCollectionViewContainerView : NSView
+
+ at property (readonly) NSCollectionView *collectionView;
+ at property (readonly) VLCLibraryCollectionViewFlowLayout *collectionViewLayout;
+ at property (readonly) VLCSubScrollView *scrollView;
+ at property (readonly) VLCLibraryVideoCollectionViewContainerViewDataSource *dataSource;
+ at property (readonly) VLCLibraryVideoCollectionViewGroupDescriptor *groupDescriptor;
+ at property (readwrite, assign, nonatomic) VLCLibraryVideoGroup videoGroup;
+ at property (readwrite, assign) NSArray<NSLayoutConstraint *> *constraintsWithSuperview;
+
+- (void)setVideoGroup:(VLCLibraryVideoGroup)group;
+
+ at end
+
+NS_ASSUME_NONNULL_END


=====================================
modules/gui/macosx/library/video-library/VLCLibraryVideoCollectionViewContainerView.m
=====================================
@@ -0,0 +1,199 @@
+/*****************************************************************************
+ * VLCLibraryVideoCollectionViewContainerView.m: MacOS X interface module
+ *****************************************************************************
+ * Copyright (C) 2022 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 "VLCLibraryVideoCollectionViewContainerView.h"
+
+#import "library/VLCLibraryCollectionViewFlowLayout.h"
+#import "library/VLCLibraryCollectionViewSupplementaryElementView.h"
+
+#import "library/video-library/VLCLibraryVideoCollectionViewContainerViewDataSource.h"
+#import "library/video-library/VLCLibraryVideoGroupDescriptor.h"
+
+#import "views/VLCSubScrollView.h"
+
+ at implementation VLCLibraryVideoCollectionViewContainerView
+
+- (instancetype)init
+{
+    self = [super init];
+
+    if(self) {
+        [self setupView];
+        [self setupDataSource];
+        [self setupCollectionViewSizeChangeListener];
+    }
+
+    return self;
+}
+
+- (void)setupView
+{
+    [self setupCollectionView];
+    [self setupScrollView];
+
+    [self addSubview:_scrollView];
+    [self addConstraints:@[
+        [NSLayoutConstraint constraintWithItem:_scrollView
+                                     attribute:NSLayoutAttributeTop
+                                     relatedBy:NSLayoutRelationEqual
+                                        toItem:self
+                                     attribute:NSLayoutAttributeTop
+                                    multiplier:1
+                                      constant:0
+        ],
+        [NSLayoutConstraint constraintWithItem:_scrollView
+                                     attribute:NSLayoutAttributeBottom
+                                     relatedBy:NSLayoutRelationEqual
+                                        toItem:self
+                                     attribute:NSLayoutAttributeBottom
+                                    multiplier:1
+                                      constant:0
+        ],
+        [NSLayoutConstraint constraintWithItem:_scrollView
+                                     attribute:NSLayoutAttributeLeft
+                                     relatedBy:NSLayoutRelationEqual
+                                        toItem:self
+                                     attribute:NSLayoutAttributeLeft
+                                    multiplier:1
+                                      constant:0
+        ],
+        [NSLayoutConstraint constraintWithItem:_scrollView
+                                     attribute:NSLayoutAttributeRight
+                                     relatedBy:NSLayoutRelationEqual
+                                        toItem:self
+                                     attribute:NSLayoutAttributeRight
+                                    multiplier:1
+                                      constant:0
+        ],
+    ]];
+
+    [self setContentHuggingPriority:NSLayoutPriorityDefaultLow
+                     forOrientation:NSLayoutConstraintOrientationHorizontal];
+    [self setContentCompressionResistancePriority:NSLayoutPriorityDefaultLow
+                                   forOrientation:NSLayoutConstraintOrientationHorizontal];
+
+    [self setContentHuggingPriority:NSLayoutPriorityDefaultHigh
+                     forOrientation:NSLayoutConstraintOrientationVertical];
+    [self setContentCompressionResistancePriority:NSLayoutPriorityDefaultHigh
+                     forOrientation:NSLayoutConstraintOrientationVertical];
+}
+
+- (void)setupCollectionView
+{
+    _collectionViewLayout = [[VLCLibraryCollectionViewFlowLayout alloc] init];
+    _collectionViewLayout.headerReferenceSize = [VLCLibraryCollectionViewSupplementaryElementView defaultHeaderSize];
+    _collectionViewLayout.itemSize = CGSizeMake(214., 260.);
+
+    _collectionView = [[NSCollectionView alloc] initWithFrame:NSZeroRect];
+    _collectionView.postsFrameChangedNotifications = YES;
+    _collectionView.collectionViewLayout = _collectionViewLayout;
+    _collectionView.selectable = YES;
+    _collectionView.allowsEmptySelection = YES;
+    _collectionView.allowsMultipleSelection = NO;
+}
+
+- (void)setupScrollView
+{
+    _scrollView = [[VLCSubScrollView alloc] init];
+    _scrollView.scrollParentY = YES;
+    _scrollView.forceHideVerticalScroller = YES;
+
+    _scrollView.translatesAutoresizingMaskIntoConstraints = NO;
+    _scrollView.documentView = _collectionView;
+}
+
+- (void)setupDataSource
+{
+    _dataSource = [[VLCLibraryVideoCollectionViewContainerViewDataSource alloc] init];
+    _dataSource.collectionView = _collectionView;
+    [_dataSource setup];
+}
+
+- (void)setupCollectionViewSizeChangeListener
+{
+    NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
+    [notificationCenter addObserver:self
+                           selector:@selector(collectionViewFrameChanged:)
+                               name:NSViewFrameDidChangeNotification
+                             object:nil];
+}
+
+- (void)setGroupDescriptor:(VLCLibraryVideoCollectionViewGroupDescriptor *)groupDescriptor
+{
+    _groupDescriptor = groupDescriptor;
+    _dataSource.groupDescriptor = groupDescriptor;
+
+    _collectionViewLayout.scrollDirection = _groupDescriptor.isHorizontalBarCollectionView ?
+                                            NSCollectionViewScrollDirectionHorizontal :
+                                            NSCollectionViewScrollDirectionVertical;
+}
+
+- (void)setVideoGroup:(VLCLibraryVideoGroup)group
+{
+    if (_groupDescriptor.group == group) {
+        return;
+    }
+
+    VLCLibraryVideoCollectionViewGroupDescriptor *descriptor = [[VLCLibraryVideoCollectionViewGroupDescriptor alloc] initWithVLCVideoLibraryGroup:group];
+    [self setGroupDescriptor:descriptor];
+}
+
+- (void)collectionViewFrameChanged:(NSNotification *)notification
+{
+    if (notification.object != self) {
+        return;
+    }
+
+    // HACK: On app init the vertical collection views will not get their heights updated properly.
+    // So let's schedule a check a bit later to correct this issue...
+    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 100 * NSEC_PER_MSEC), dispatch_get_main_queue(), ^{
+        [self invalidateIntrinsicContentSize];
+    });
+}
+
+- (NSSize)intrinsicContentSize
+{
+    NSSize collectionViewContentSize = _collectionViewLayout.collectionViewContentSize;
+    NSEdgeInsets scrollViewInsets = _collectionView.enclosingScrollView.contentInsets;
+    NSEdgeInsets collectionViewLayoutInset = _collectionViewLayout.sectionInset;
+    CGFloat insetsHeight = scrollViewInsets.top +
+                           scrollViewInsets.bottom +
+                           collectionViewLayoutInset.top +
+                           collectionViewLayoutInset.bottom +
+                           15; // Account for the scrollbar size
+
+    if (collectionViewContentSize.height == 0 || _groupDescriptor.isHorizontalBarCollectionView) {
+        CGFloat fallback = _collectionViewLayout.itemSize.height + insetsHeight;
+
+        if (fallback <= 0) {
+            NSLog(@"Unable to provide reasonable fallback or accurate rowheight -- providing rough rowheight");
+            fallback = 400;
+        }
+
+        return NSMakeSize(fallback, fallback);
+    }
+
+    collectionViewContentSize.height += insetsHeight;
+    return collectionViewContentSize;
+}
+
+ at end


=====================================
modules/gui/macosx/library/video-library/VLCLibraryVideoCollectionViewContainerViewDataSource.h
=====================================
@@ -0,0 +1,41 @@
+/*****************************************************************************
+ * VLCLibraryVideoCollectionViewTableViewCellDataSource.h: MacOS X interface module
+ *****************************************************************************
+ * Copyright (C) 2022 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>
+
+ at class VLCLibraryVideoCollectionViewContainerView;
+ at class VLCLibraryVideoCollectionViewGroupDescriptor;
+
+NS_ASSUME_NONNULL_BEGIN
+
+ at interface VLCLibraryVideoCollectionViewContainerViewDataSource : NSObject <NSCollectionViewDataSource, NSCollectionViewDelegate>
+
+ at property (readwrite, assign) NSCollectionView *collectionView;
+ at property (readwrite, assign, nonatomic) VLCLibraryVideoCollectionViewGroupDescriptor *groupDescriptor;
+ at property (readwrite, assign) VLCLibraryVideoCollectionViewContainerView *parentCell;
+
+- (void)setup;
+- (void)reloadData;
+
+ at end
+
+NS_ASSUME_NONNULL_END


=====================================
modules/gui/macosx/library/VLCLibraryVideoDataSource.m → modules/gui/macosx/library/video-library/VLCLibraryVideoCollectionViewContainerViewDataSource.m
=====================================
@@ -1,9 +1,9 @@
 /*****************************************************************************
- * VLCLibraryVideoDataSource.m: MacOS X interface module
+ * VLCLibraryVideoCollectionViewContainerViewDataSource.m: MacOS X interface module
  *****************************************************************************
- * Copyright (C) 2019 VLC authors and VideoLAN
+ * Copyright (C) 2022 VLC authors and VideoLAN
  *
- * Authors: Felix Paul Kühne <fkuehne # videolan -dot- org>
+ * 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
@@ -20,29 +20,29 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 
-#import "VLCLibraryVideoDataSource.h"
+#import "VLCLibraryVideoCollectionViewContainerViewDataSource.h"
 
 #import "library/VLCLibraryCollectionViewFlowLayout.h"
 #import "library/VLCLibraryCollectionViewItem.h"
 #import "library/VLCLibraryCollectionViewMediaItemSupplementaryDetailView.h"
 #import "library/VLCLibraryCollectionViewSupplementaryElementView.h"
-#import "library/VLCLibraryModel.h"
+#import "library/VLCLibraryController.h"
 #import "library/VLCLibraryDataTypes.h"
-#import "library/VLCLibraryTableCellView.h"
+#import "library/VLCLibraryModel.h"
+
+#import "library/video-library/VLCLibraryVideoGroupDescriptor.h"
 
-#import "main/CompatibilityFixes.h"
-#import "extensions/NSString+Helpers.h"
+#import "main/VLCMain.h"
 
- at interface VLCLibraryVideoDataSource ()
+ at interface VLCLibraryVideoCollectionViewContainerViewDataSource ()
 {
-    NSArray *_recentsArray;
-    NSArray *_libraryArray;
+    NSArray *_collectionArray;
     VLCLibraryCollectionViewFlowLayout *_collectionViewFlowLayout;
+    VLCLibraryModel *_libraryModel;
 }
-
 @end
 
- at implementation VLCLibraryVideoDataSource
+ at implementation VLCLibraryVideoCollectionViewContainerViewDataSource
 
 - (instancetype)init
 {
@@ -57,6 +57,7 @@
                                selector:@selector(libraryModelUpdated:)
                                    name:VLCLibraryModelRecentMediaListUpdated
                                  object:nil];
+        _libraryModel = [VLCMain sharedInstance].libraryController.libraryModel;
     }
     return self;
 }
@@ -68,60 +69,61 @@
 
 - (void)reloadData
 {
-    if(!_libraryModel) {
+    if(!_collectionView || !_groupDescriptor) {
+        NSLog(@"Null collection view or video group descriptor");
         return;
     }
-    
-    [_collectionViewFlowLayout resetLayout];
-    
+
     dispatch_async(dispatch_get_main_queue(), ^{
-        _recentsArray = [_libraryModel listOfRecentMedia];
-        _libraryArray = [_libraryModel listOfVideoMedia];
-        [_libraryMediaCollectionView reloadData];
-        [_groupsTableView reloadData];
-        [_groupSelectionTableView reloadData];
+        NSAssert(self->_groupDescriptor.libraryModelDataMethodSignature, @"Group descriptor's library model data method signature cannot be nil");
+
+        NSInvocation *modelDataInvocation = [NSInvocation invocationWithMethodSignature:self->_groupDescriptor.libraryModelDataMethodSignature];
+        modelDataInvocation.selector = self->_groupDescriptor.libraryModelDataSelector;
+        [modelDataInvocation invokeWithTarget:self->_libraryModel];
+        [modelDataInvocation getReturnValue:&self->_collectionArray];
+
+        [self->_collectionView reloadData];
     });
 }
 
-- (void)setup
+- (void)setGroupDescriptor:(VLCLibraryVideoCollectionViewGroupDescriptor *)groupDescriptor
 {
-    [self setupCollectionView];
-    [self setupTableViews];
+    if(!groupDescriptor) {
+        NSLog(@"Invalid group descriptor");
+        return;
+    }
+
+    _groupDescriptor = groupDescriptor;
+    [self reloadData];
 }
 
-- (void)setupCollectionView
+- (void)setup
 {
-    _libraryMediaCollectionView.dataSource = self;
-    _libraryMediaCollectionView.delegate = self;
-    
-    [_libraryMediaCollectionView registerClass:[VLCLibraryCollectionViewItem class] forItemWithIdentifier:VLCLibraryCellIdentifier];
-    [_libraryMediaCollectionView registerClass:[VLCLibraryCollectionViewSupplementaryElementView class]
-                    forSupplementaryViewOfKind:NSCollectionElementKindSectionHeader
-                                withIdentifier:VLCLibrarySupplementaryElementViewIdentifier];
-    
-    NSNib *mediaItemSupplementaryDetailView = [[NSNib alloc] initWithNibNamed:@"VLCLibraryCollectionViewMediaItemSupplementaryDetailView" bundle:nil];
-    [_libraryMediaCollectionView registerNib:mediaItemSupplementaryDetailView
-                  forSupplementaryViewOfKind:VLCLibraryCollectionViewMediaItemSupplementaryDetailViewKind
-                              withIdentifier:VLCLibraryCollectionViewMediaItemSupplementaryDetailViewIdentifier];
+    VLCLibraryCollectionViewFlowLayout *collectionViewLayout = (VLCLibraryCollectionViewFlowLayout*)_collectionView.collectionViewLayout;
+    NSAssert(collectionViewLayout, @"Collection view must have a VLCLibraryCollectionViewFlowLayout!");
+
+    _collectionViewFlowLayout = collectionViewLayout;
+    _collectionView.dataSource = self;
+    _collectionView.delegate = self;
+
+    [_collectionView registerClass:[VLCLibraryCollectionViewItem class]
+             forItemWithIdentifier:VLCLibraryCellIdentifier];
 
-    _collectionViewFlowLayout = [[VLCLibraryCollectionViewFlowLayout alloc] init];
-    _collectionViewFlowLayout.headerReferenceSize = [VLCLibraryCollectionViewSupplementaryElementView defaultHeaderSize];
-    _libraryMediaCollectionView.collectionViewLayout = _collectionViewFlowLayout;
+    [_collectionView registerClass:[VLCLibraryCollectionViewSupplementaryElementView class]
+        forSupplementaryViewOfKind:NSCollectionElementKindSectionHeader
+                    withIdentifier:VLCLibrarySupplementaryElementViewIdentifier];
+
+    NSNib *mediaItemSupplementaryDetailView = [[NSNib alloc] initWithNibNamed:@"VLCLibraryCollectionViewMediaItemSupplementaryDetailView" bundle:nil];
+    [_collectionView registerNib:mediaItemSupplementaryDetailView
+      forSupplementaryViewOfKind:VLCLibraryCollectionViewMediaItemSupplementaryDetailViewKind
+                  withIdentifier:VLCLibraryCollectionViewMediaItemSupplementaryDetailViewIdentifier];
 }
 
-- (void)setupTableViews
+- (NSInteger)numberOfSectionsInCollectionView:(NSCollectionView *)collectionView
 {
-    _groupsTableView.dataSource = self;
-    _groupsTableView.delegate = self;
-    _groupsTableView.target = self;
-    
-    _groupSelectionTableView.dataSource = self;
-    _groupSelectionTableView.delegate = self;
-    _groupSelectionTableView.target = self;
+    return 1;
 }
 
-#pragma mark - collection view data source and delegation
-
 - (NSInteger)collectionView:(NSCollectionView *)collectionView
      numberOfItemsInSection:(NSInteger)section
 {
@@ -129,46 +131,45 @@
         return 0;
     }
 
-    switch(section) {
-        case VLCVideoLibraryRecentsSection:
-            return [_libraryModel numberOfRecentMedia];
-        case VLCVideoLibraryLibrarySection:
-            return [_libraryModel numberOfVideoMedia];
-        default:
-            NSAssert(1, @"Reached unreachable case for video library section");
-            break;
-    }
-}
-
-- (NSInteger)numberOfSectionsInCollectionView:(NSCollectionView *)collectionView
-{
-    return 2;
+    return _collectionArray.count;
 }
 
 - (NSCollectionViewItem *)collectionView:(NSCollectionView *)collectionView
      itemForRepresentedObjectAtIndexPath:(NSIndexPath *)indexPath
 {
     VLCLibraryCollectionViewItem *viewItem = [collectionView makeItemWithIdentifier:VLCLibraryCellIdentifier forIndexPath:indexPath];
+    viewItem.representedItem = _collectionArray[indexPath.item];
+    return viewItem;
+}
+
+- (NSView *)collectionView:(NSCollectionView *)collectionView
+viewForSupplementaryElementOfKind:(NSCollectionViewSupplementaryElementKind)kind
+               atIndexPath:(NSIndexPath *)indexPath
+{
+    if([kind isEqualToString:NSCollectionElementKindSectionHeader]) {
+        VLCLibraryCollectionViewSupplementaryElementView *sectionHeadingView = [collectionView makeSupplementaryViewOfKind:kind
+                                                                                                            withIdentifier:VLCLibrarySupplementaryElementViewIdentifier
+                                                                                                              forIndexPath:indexPath];
+
+        sectionHeadingView.stringValue = _groupDescriptor.name;
+        return sectionHeadingView;
+
+    } else if ([kind isEqualToString:VLCLibraryCollectionViewMediaItemSupplementaryDetailViewKind]) {
+        VLCLibraryCollectionViewMediaItemSupplementaryDetailView* mediaItemSupplementaryDetailView = [collectionView makeSupplementaryViewOfKind:kind withIdentifier:VLCLibraryCollectionViewMediaItemSupplementaryDetailViewKind forIndexPath:indexPath];
 
-    switch(indexPath.section) {
-        case VLCVideoLibraryRecentsSection:
-            viewItem.representedItem = _recentsArray[indexPath.item];
-            break;
-        case VLCVideoLibraryLibrarySection:
-            viewItem.representedItem = _libraryArray[indexPath.item];
-            break;
-        default:
-            NSAssert(1, @"Reached unreachable case for video library section");
-            break;
+        mediaItemSupplementaryDetailView.representedMediaItem = _collectionArray[indexPath.item];
+        mediaItemSupplementaryDetailView.selectedItem = [collectionView itemAtIndexPath:indexPath];
+        return mediaItemSupplementaryDetailView;
     }
 
-    return viewItem;
+    return nil;
 }
 
 - (void)collectionView:(NSCollectionView *)collectionView didSelectItemsAtIndexPaths:(NSSet<NSIndexPath *> *)indexPaths
 {
     NSIndexPath *indexPath = indexPaths.anyObject;
     if (!indexPath) {
+        NSLog(@"Bad index path on item selection");
         return;
     }
 
@@ -179,58 +180,13 @@
 {
     NSIndexPath *indexPath = indexPaths.anyObject;
     if (!indexPath) {
+        NSLog(@"Bad index path on item deselection");
         return;
     }
 
     [_collectionViewFlowLayout collapseDetailSectionAtIndex:indexPath];
 }
 
-- (NSView *)collectionView:(NSCollectionView *)collectionView
-viewForSupplementaryElementOfKind:(NSCollectionViewSupplementaryElementKind)kind
-               atIndexPath:(NSIndexPath *)indexPath
-{
-    if([kind isEqualToString:NSCollectionElementKindSectionHeader]) {
-        VLCLibraryCollectionViewSupplementaryElementView *sectionHeadingView = [collectionView makeSupplementaryViewOfKind:kind
-                                                                                                            withIdentifier:VLCLibrarySupplementaryElementViewIdentifier
-                                                                                                              forIndexPath:indexPath];
-        
-        switch(indexPath.section) {
-            case VLCVideoLibraryRecentsSection:
-                sectionHeadingView.stringValue = _NS("Recent");
-                break;
-            case VLCVideoLibraryLibrarySection:
-                sectionHeadingView.stringValue = _NS("Library");
-                break;
-            default:
-                NSAssert(1, @"Reached unreachable case for video library section");
-                break;
-        }
-                
-        return sectionHeadingView;
-        
-    } else if ([kind isEqualToString:VLCLibraryCollectionViewMediaItemSupplementaryDetailViewKind]) {
-        VLCLibraryCollectionViewMediaItemSupplementaryDetailView* mediaItemSupplementaryDetailView = [collectionView makeSupplementaryViewOfKind:kind withIdentifier:VLCLibraryCollectionViewMediaItemSupplementaryDetailViewKind forIndexPath:indexPath];
-        
-        switch(indexPath.section) {
-            case VLCVideoLibraryRecentsSection:
-                mediaItemSupplementaryDetailView.representedMediaItem = _recentsArray[indexPath.item];
-                break;
-            case VLCVideoLibraryLibrarySection:
-                mediaItemSupplementaryDetailView.representedMediaItem = _libraryArray[indexPath.item];
-                break;
-            default:
-                NSAssert(1, @"Reached unreachable case for video library section");
-                break;
-        }
-        
-        mediaItemSupplementaryDetailView.selectedItem = [collectionView itemAtIndexPath:indexPath];
-        return mediaItemSupplementaryDetailView;
-    }
-
-    return nil;
-}
-
-#pragma mark - drag and drop support
 
 - (BOOL)collectionView:(NSCollectionView *)collectionView
 canDragItemsAtIndexPaths:(NSSet<NSIndexPath *> *)indexPaths
@@ -247,7 +203,7 @@ writeItemsAtIndexPaths:(NSSet<NSIndexPath *> *)indexPaths
     NSMutableArray *encodedLibraryItemsArray = [NSMutableArray arrayWithCapacity:numberOfIndexPaths];
     NSMutableArray *filePathsArray = [NSMutableArray arrayWithCapacity:numberOfIndexPaths];
     for (NSIndexPath *indexPath in indexPaths) {
-        VLCMediaLibraryMediaItem *mediaItem = _libraryArray[indexPath.item];
+        VLCMediaLibraryMediaItem *mediaItem = _collectionArray[indexPath.item];
         [encodedLibraryItemsArray addObject:mediaItem];
 
         VLCMediaLibraryFile *file = mediaItem.files.firstObject;
@@ -265,60 +221,4 @@ writeItemsAtIndexPaths:(NSSet<NSIndexPath *> *)indexPaths
     return YES;
 }
 
-#pragma mark - table view data source and delegation
-
-- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
-{
-    if (tableView == _groupsTableView) {
-        return 2;
-    } else if (tableView == _groupSelectionTableView && _groupsTableView.selectedRow > -1) {
-        switch(_groupsTableView.selectedRow) {
-            case VLCVideoLibraryRecentsSection:
-                return _recentsArray.count;
-            case VLCVideoLibraryLibrarySection:
-                return _libraryArray.count;
-            default:
-                NSAssert(1, @"Reached unreachable case for video library section");
-                break;
-        }
-    }
-    
-    return 0;
-}
-
-- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
-{
-    VLCLibraryTableCellView *cellView = [tableView makeViewWithIdentifier:@"VLCVideoLibraryTableViewCellIdentifier" owner:self];
-    
-    if (!cellView) {
-        cellView = [VLCLibraryTableCellView fromNibWithOwner:self];
-        cellView.identifier = @"VLCVideoLibraryTableViewCellIdentifier";
-    }
-    
-    if (tableView == _groupsTableView) {
-        cellView.representedVideoLibrarySection = row;
-    } else if (tableView == _groupSelectionTableView && _groupsTableView.selectedRow > -1) {
-        switch(_groupsTableView.selectedRow) {
-            case VLCVideoLibraryRecentsSection:
-                cellView.representedItem = _recentsArray[row];
-                break;
-            case VLCVideoLibraryLibrarySection:
-                cellView.representedItem = _libraryArray[row];
-                break;
-            default:
-                NSAssert(1, @"Reached unreachable case for video library section");
-                break;
-        }
-    }
-    
-    return cellView;
-}
-
-- (void)tableViewSelectionDidChange:(NSNotification *)notification
-{
-    if(notification.object == _groupsTableView) {
-        [_groupSelectionTableView reloadData];
-    }
-}
-
 @end


=====================================
modules/gui/macosx/library/video-library/VLCLibraryVideoCollectionViewsStackViewController.h
=====================================
@@ -0,0 +1,41 @@
+/*****************************************************************************
+ * VLCLibraryVideoCollectionViewsStackViewController.h: MacOS X interface module
+ *****************************************************************************
+ * Copyright (C) 2022 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 VLCLibraryVideoCollectionViewsStackViewController : NSObject
+
+ at property (readwrite, assign, nonatomic) NSSize collectionViewItemSize;
+ at property (readwrite, assign, nonatomic) CGFloat collectionViewMinimumLineSpacing;
+ at property (readwrite, assign, nonatomic) CGFloat collectionViewMinimumInteritemSpacing;
+ at property (readwrite, assign, nonatomic) NSEdgeInsets collectionViewSectionInset;
+
+ at property (readwrite, assign, nonatomic) NSStackView *collectionsStackView;
+ at property (readwrite, assign, nonatomic) NSScrollView *collectionsStackViewScrollView;
+
+- (void)reloadData;
+
+ at end
+
+NS_ASSUME_NONNULL_END


=====================================
modules/gui/macosx/library/video-library/VLCLibraryVideoCollectionViewsStackViewController.m
=====================================
@@ -0,0 +1,173 @@
+/*****************************************************************************
+ * VLCLibraryVideoCollectionViewsStackViewController.m: MacOS X interface module
+ *****************************************************************************
+ * Copyright (C) 2022 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 "VLCLibraryVideoCollectionViewsStackViewController.h"
+
+#import "library/VLCLibraryCollectionViewFlowLayout.h"
+#import "library/VLCLibraryCollectionViewSupplementaryElementView.h"
+#import "library/VLCLibraryModel.h"
+
+#import "library/video-library/VLCLibraryVideoCollectionViewContainerView.h"
+#import "library/video-library/VLCLibraryVideoCollectionViewContainerViewDataSource.h"
+#import "library/video-library/VLCLibraryVideoGroupDescriptor.h"
+
+#import "views/VLCSubScrollView.h"
+
+ at interface VLCLibraryVideoCollectionViewsStackViewController()
+{
+    NSArray *_collectionViewContainers;
+}
+ at end
+
+ at implementation VLCLibraryVideoCollectionViewsStackViewController
+
+- (instancetype)init
+{
+    self = [super init];
+    if (self) {
+        [self setup];
+    }
+    return self;
+}
+
+- (void)setup
+{
+    [self generateCollectionViewContainers];
+}
+
+- (void)generateCollectionViewContainers
+{
+    NSMutableArray *collectionViewContainers = [[NSMutableArray alloc] init];
+
+    for (NSUInteger i = VLCLibraryVideoRecentsGroup; i < VLCLibraryVideoSentinel; ++i) {
+        VLCLibraryVideoCollectionViewContainerView *containerView = [[VLCLibraryVideoCollectionViewContainerView alloc] init];
+        containerView.videoGroup = i;
+        [collectionViewContainers addObject:containerView];
+    }
+
+    _collectionViewContainers = collectionViewContainers;
+}
+
+- (void)reloadData
+{
+    dispatch_async(dispatch_get_main_queue(), ^{
+        for (VLCLibraryVideoCollectionViewContainerView *containerView in self->_collectionViewContainers) {
+            [containerView.collectionView reloadData];
+        }
+    });
+}
+
+- (void)setCollectionsStackView:(NSStackView *)collectionsStackView
+{
+    NSParameterAssert(collectionsStackView);
+
+    if (_collectionsStackView) {
+        for (VLCLibraryVideoCollectionViewContainerView *containerView in _collectionViewContainers) {
+            if (containerView.constraintsWithSuperview.count > 0) {
+                [_collectionsStackView removeConstraints:containerView.constraintsWithSuperview];
+            }
+        }
+    }
+
+    _collectionsStackView = collectionsStackView;
+    _collectionsStackView.spacing = 20.;
+    _collectionsStackView.orientation = NSUserInterfaceLayoutOrientationVertical;
+    _collectionsStackView.alignment = NSLayoutAttributeLeading;
+    _collectionsStackView.distribution = NSStackViewDistributionFill;
+    [_collectionsStackView setHuggingPriority:NSLayoutPriorityDefaultHigh
+                               forOrientation:NSLayoutConstraintOrientationVertical];
+
+
+    for (VLCLibraryVideoCollectionViewContainerView *containerView in _collectionViewContainers) {
+        containerView.translatesAutoresizingMaskIntoConstraints = NO;
+        NSArray<NSLayoutConstraint*> *constraintsWithSuperview = @[
+            [NSLayoutConstraint constraintWithItem:containerView
+                                         attribute:NSLayoutAttributeLeft
+                                         relatedBy:NSLayoutRelationEqual
+                                            toItem:_collectionsStackView
+                                         attribute:NSLayoutAttributeLeft
+                                        multiplier:1
+                                          constant:0
+            ],
+            [NSLayoutConstraint constraintWithItem:containerView
+                                         attribute:NSLayoutAttributeRight
+                                         relatedBy:NSLayoutRelationEqual
+                                            toItem:_collectionsStackView
+                                         attribute:NSLayoutAttributeRight
+                                        multiplier:1
+                                          constant:0
+            ],
+        ];
+        containerView.constraintsWithSuperview = constraintsWithSuperview;
+        [_collectionsStackView addConstraints:constraintsWithSuperview];
+        [_collectionsStackView addArrangedSubview:containerView];
+    }
+}
+
+- (void)setCollectionsStackViewScrollView:(NSScrollView *)newScrollView
+{
+    NSParameterAssert(newScrollView);
+
+    _collectionsStackViewScrollView = newScrollView;
+
+    for (VLCLibraryVideoCollectionViewContainerView *containerView in _collectionViewContainers) {
+        containerView.scrollView.parentScrollView = _collectionsStackViewScrollView;
+    }
+}
+
+- (void)setCollectionViewItemSize:(NSSize)collectionViewItemSize
+{
+    _collectionViewItemSize = collectionViewItemSize;
+
+    for (VLCLibraryVideoCollectionViewContainerView *containerView in _collectionViewContainers) {
+        containerView.collectionViewLayout.itemSize = collectionViewItemSize;
+    }
+}
+
+- (void)setCollectionViewSectionInset:(NSEdgeInsets)collectionViewSectionInset
+{
+    _collectionViewSectionInset = collectionViewSectionInset;
+
+    for (VLCLibraryVideoCollectionViewContainerView *containerView in _collectionViewContainers) {
+        containerView.collectionViewLayout.sectionInset = collectionViewSectionInset;
+    }
+}
+
+- (void)setCollectionViewMinimumLineSpacing:(CGFloat)collectionViewMinimumLineSpacing
+{
+    _collectionViewMinimumLineSpacing = collectionViewMinimumLineSpacing;
+
+    for (VLCLibraryVideoCollectionViewContainerView *containerView in _collectionViewContainers) {
+        containerView.collectionViewLayout.minimumLineSpacing = collectionViewMinimumLineSpacing;
+    }
+}
+
+- (void) setCollectionViewMinimumInteritemSpacing:(CGFloat)collectionViewMinimumInteritemSpacing
+{
+    _collectionViewMinimumInteritemSpacing = collectionViewMinimumInteritemSpacing;
+
+    for (VLCLibraryVideoCollectionViewContainerView *containerView in _collectionViewContainers) {
+        containerView.collectionViewLayout.minimumInteritemSpacing = collectionViewMinimumInteritemSpacing;
+    }
+}
+
+ at end


=====================================
modules/gui/macosx/library/video-library/VLCLibraryVideoGroupDescriptor.h
=====================================
@@ -0,0 +1,49 @@
+/*****************************************************************************
+ * VLCLibraryVideoGroupDescriptor.h: MacOS X interface module
+ *****************************************************************************
+ * Copyright (C) 2022 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>
+
+#import "library/video-library/VLCLibraryVideoCollectionViewsStackViewController.h"
+
+typedef NS_ENUM(NSUInteger, VLCLibraryVideoGroup) {
+    VLCLibraryVideoInvalidGroup = 0,
+    VLCLibraryVideoRecentsGroup,
+    VLCLibraryVideoLibraryGroup,
+    VLCLibraryVideoSentinel,
+};
+
+NS_ASSUME_NONNULL_BEGIN
+
+ at interface VLCLibraryVideoCollectionViewGroupDescriptor : NSObject
+
+ at property (readonly) VLCLibraryVideoGroup group;
+ at property (readonly) SEL libraryModelDataSelector;
+ at property (readonly) NSMethodSignature *libraryModelDataMethodSignature;
+ at property (readonly) NSNotificationName libraryModelUpdatedNotificationName;
+ at property (readonly) NSString *name;
+ at property (readonly) BOOL isHorizontalBarCollectionView;
+
+- (instancetype)initWithVLCVideoLibraryGroup:(VLCLibraryVideoGroup)group;
+
+ at end
+
+NS_ASSUME_NONNULL_END


=====================================
modules/gui/macosx/library/video-library/VLCLibraryVideoGroupDescriptor.m
=====================================
@@ -0,0 +1,63 @@
+/*****************************************************************************
+ * VLCLibraryVideoGroupDescriptor.m: MacOS X interface module
+ *****************************************************************************
+ * Copyright (C) 2022 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 "VLCLibraryVideoGroupDescriptor.h"
+
+#import "extensions/NSString+Helpers.h"
+
+#import "library/VLCLibraryModel.h"
+
+ at implementation VLCLibraryVideoCollectionViewGroupDescriptor
+
+- (instancetype)initWithVLCVideoLibraryGroup:(VLCLibraryVideoGroup)group
+{
+    self = [super init];
+
+    if (self) {
+        _group = group;
+
+        switch (_group) {
+            case VLCLibraryVideoRecentsGroup:
+                _libraryModelUpdatedNotificationName = VLCLibraryModelRecentMediaListUpdated;
+                _libraryModelDataSelector = @selector(listOfRecentMedia);
+                _isHorizontalBarCollectionView = YES;
+                _name = _NS("Recents");
+                break;
+            case VLCLibraryVideoLibraryGroup:
+                _libraryModelUpdatedNotificationName = VLCLibraryModelVideoMediaListUpdated;
+                _libraryModelDataSelector = @selector(listOfVideoMedia);
+                _isHorizontalBarCollectionView = NO;
+                _name = _NS("Library");
+                break;
+            default:
+                NSAssert(1, @"Cannot construct group descriptor from invalid VLCLibraryVideoGroup value");
+                _group = VLCLibraryVideoInvalidGroup;
+                break;
+        }
+
+        _libraryModelDataMethodSignature = [VLCLibraryModel instanceMethodSignatureForSelector:_libraryModelDataSelector];
+    }
+
+    return self;
+}
+
+ at end


=====================================
modules/gui/macosx/library/VLCLibraryVideoDataSource.h → modules/gui/macosx/library/video-library/VLCLibraryVideoTableViewDataSource.h
=====================================
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * VLCLibraryVideoDataSource.h: MacOS X interface module
+ * VVLCLibraryVideoTableViewDataSource.h: MacOS X interface module
  *****************************************************************************
  * Copyright (C) 2019 VLC authors and VideoLAN
  *
@@ -22,21 +22,13 @@
 
 #import <Cocoa/Cocoa.h>
 
-#import "VLCLibraryTableView.h"
-
-typedef NS_ENUM(NSUInteger, VLCVideoLibrarySection) {
-    VLCVideoLibraryRecentsSection = 0,
-    VLCVideoLibraryLibrarySection,
-};
-
 NS_ASSUME_NONNULL_BEGIN
 
 @class VLCLibraryModel;
 
- at interface VLCLibraryVideoDataSource : NSObject <NSTableViewDataSource, NSTableViewDelegate, NSCollectionViewDataSource, NSCollectionViewDelegate>
+ at interface VLCLibraryVideoTableViewDataSource : NSObject <NSTableViewDataSource, NSTableViewDelegate>
 
 @property (readwrite, assign) VLCLibraryModel *libraryModel;
- at property (readwrite, assign) NSCollectionView *libraryMediaCollectionView;
 @property (readwrite, assign) NSTableView *groupsTableView;
 @property (readwrite, assign) NSTableView *groupSelectionTableView;
 


=====================================
modules/gui/macosx/library/video-library/VLCLibraryVideoTableViewDataSource.m
=====================================
@@ -0,0 +1,159 @@
+/*****************************************************************************
+ * VLCLibraryVideoTableViewDataSource.m: MacOS X interface module
+ *****************************************************************************
+ * Copyright (C) 2019 VLC authors and VideoLAN
+ *
+ * Authors: Felix Paul Kühne <fkuehne # videolan -dot- org>
+ *
+ * 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 "VLCLibraryVideoTableViewDataSource.h"
+
+#import "library/VLCLibraryCollectionViewFlowLayout.h"
+#import "library/VLCLibraryCollectionViewItem.h"
+#import "library/VLCLibraryCollectionViewMediaItemSupplementaryDetailView.h"
+#import "library/VLCLibraryCollectionViewSupplementaryElementView.h"
+#import "library/VLCLibraryModel.h"
+#import "library/VLCLibraryDataTypes.h"
+#import "library/VLCLibraryTableCellView.h"
+
+#import "library/video-library/VLCLibraryVideoGroupDescriptor.h"
+
+#import "main/CompatibilityFixes.h"
+#import "extensions/NSString+Helpers.h"
+
+ at interface VLCLibraryVideoTableViewDataSource ()
+{
+    NSArray *_recentsArray;
+    NSArray *_libraryArray;
+    VLCLibraryCollectionViewFlowLayout *_collectionViewFlowLayout;
+}
+
+ at end
+
+ at implementation VLCLibraryVideoTableViewDataSource
+
+- (instancetype)init
+{
+    self = [super init];
+    if(self) {
+        NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
+        [notificationCenter addObserver:self
+                               selector:@selector(libraryModelUpdated:)
+                                   name:VLCLibraryModelVideoMediaListUpdated
+                                 object:nil];
+        [notificationCenter addObserver:self
+                               selector:@selector(libraryModelUpdated:)
+                                   name:VLCLibraryModelRecentMediaListUpdated
+                                 object:nil];
+    }
+    return self;
+}
+
+- (void)libraryModelUpdated:(NSNotification *)aNotification
+{
+    [self reloadData];
+}
+
+- (void)reloadData
+{
+    if(!_libraryModel) {
+        return;
+    }
+    
+    [_collectionViewFlowLayout resetLayout];
+    
+    dispatch_async(dispatch_get_main_queue(), ^{
+        self->_recentsArray = [self->_libraryModel listOfRecentMedia];
+        self->_libraryArray = [self->_libraryModel listOfVideoMedia];
+        [self->_groupsTableView reloadData];
+        [self->_groupSelectionTableView reloadData];
+    });
+}
+
+- (void)setup
+{
+    [self setupTableViews];
+}
+
+- (void)setupTableViews
+{
+    _groupsTableView.dataSource = self;
+    _groupsTableView.delegate = self;
+    _groupsTableView.target = self;
+    
+    _groupSelectionTableView.dataSource = self;
+    _groupSelectionTableView.delegate = self;
+    _groupSelectionTableView.target = self;
+}
+
+#pragma mark - table view data source and delegation
+
+- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
+{
+    if (tableView == _groupsTableView) {
+        return 2;
+    } else if (tableView == _groupSelectionTableView && _groupsTableView.selectedRow > -1) {
+        switch(_groupsTableView.selectedRow + 1) { // Group 0 is invalid so add one
+            case VLCLibraryVideoRecentsGroup:
+                return _recentsArray.count;
+            case VLCLibraryVideoLibraryGroup:
+                return _libraryArray.count;
+            default:
+                NSAssert(1, @"Reached unreachable case for video library section");
+                break;
+        }
+    }
+    
+    return 0;
+}
+
+- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
+{
+    VLCLibraryTableCellView *cellView = [tableView makeViewWithIdentifier:@"VLCVideoLibraryTableViewCellIdentifier" owner:self];
+    
+    if (!cellView) {
+        cellView = [VLCLibraryTableCellView fromNibWithOwner:self];
+        cellView.identifier = @"VLCVideoLibraryTableViewCellIdentifier";
+    }
+    
+    if (tableView == _groupsTableView) {
+        cellView.representedVideoLibrarySection = row;
+    } else if (tableView == _groupSelectionTableView && _groupsTableView.selectedRow > -1) {
+        switch(_groupsTableView.selectedRow + 1) { // Group 0 is invalid so add one
+            case VLCLibraryVideoRecentsGroup:
+                cellView.representedItem = _recentsArray[row];
+                break;
+            case VLCLibraryVideoLibraryGroup:
+                cellView.representedItem = _libraryArray[row];
+                break;
+            default:
+                NSAssert(1, @"Reached unreachable case for video library section");
+                break;
+        }
+    }
+    
+    return cellView;
+}
+
+- (void)tableViewSelectionDidChange:(NSNotification *)notification
+{
+    if(notification.object == _groupsTableView) {
+        [_groupSelectionTableView reloadData];
+    }
+}
+
+ at end


=====================================
modules/gui/macosx/views/VLCSubScrollView.h
=====================================
@@ -32,6 +32,11 @@ NS_ASSUME_NONNULL_BEGIN
 @property (readwrite, assign) BOOL scrollParentY;
 @property (readwrite, assign) BOOL scrollParentX;
 
+// Scroll views containing collection views can disobey hasVerticalScroller -> NO.
+// This lets us forcefully override this behaviour
+ at property (readwrite, assign) BOOL forceHideVerticalScroller;
+ at property (readwrite, assign) BOOL forceHideHorizontalScroller;
+
 @end
 
 NS_ASSUME_NONNULL_END


=====================================
modules/gui/macosx/views/VLCSubScrollView.m
=====================================
@@ -62,4 +62,22 @@
     }
 }
 
+- (BOOL)hasVerticalScroller
+{
+    if (_forceHideVerticalScroller) {
+        return NO;
+    }
+
+    return [super hasVerticalScroller];
+}
+
+- (BOOL)hasHorizontalScroller
+{
+    if (_forceHideHorizontalScroller) {
+        return NO;
+    }
+
+    return [super hasHorizontalScroller];
+}
+
 @end


=====================================
po/POTFILES.in
=====================================
@@ -482,8 +482,10 @@ modules/gui/macosx/library/VLCLibrarySortingMenuController.h
 modules/gui/macosx/library/VLCLibrarySortingMenuController.m
 modules/gui/macosx/library/VLCLibraryTableCellView.h
 modules/gui/macosx/library/VLCLibraryTableCellView.m
-modules/gui/macosx/library/VLCLibraryVideoDataSource.h
-modules/gui/macosx/library/VLCLibraryVideoDataSource.m
+modules/gui/macosx/library/video-library/VLCLibraryVideoGroupDescriptor.h
+modules/gui/macosx/library/video-library/VLCLibraryVideoGroupDescriptor.m
+modules/gui/macosx/library/video-library/VLCLibraryVideoTableViewDataSource.h
+modules/gui/macosx/library/video-library/VLCLibraryVideoTableViewDataSource.m
 modules/gui/macosx/library/VLCLibraryWindow.h
 modules/gui/macosx/library/VLCLibraryWindow.m
 modules/gui/macosx/main/CompatibilityFixes.h



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/582570aad10b0dda1a725039ab6c35dc3e9d51c3...57a72ded4b0476dbe7f5f9c2dd427d491a4e4cc8

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/582570aad10b0dda1a725039ab6c35dc3e9d51c3...57a72ded4b0476dbe7f5f9c2dd427d491a4e4cc8
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