[vlc-commits] [Git][videolan/vlc][master] 10 commits: macosx: Implement base favorited and setFavorited and toggleFavorite in abstract media library item

Steve Lhomme (@robUx4) gitlab at videolan.org
Sun Jul 20 07:00:13 UTC 2025



Steve Lhomme pushed to branch master at VideoLAN / VLC


Commits:
a670ec20 by Claudio Cambra at 2025-07-20T06:11:34+00:00
macosx: Implement base favorited and setFavorited and toggleFavorite in abstract media library item

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

- - - - -
d5d5c35e by Claudio Cambra at 2025-07-20T06:11:34+00:00
macosx: Implement favorite-related features polymorphically in media library item protocol

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

- - - - -
5c4967c5 by Claudio Cambra at 2025-07-20T06:11:34+00:00
macosx: Update UI elements to apply favorite status via polymorphic interface

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

- - - - -
1ece1efb by Claudio Cambra at 2025-07-20T06:11:34+00:00
macosx: Deduplicate code in setting favorites for various library items

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

- - - - -
79cdc64e by Claudio Cambra at 2025-07-20T06:11:34+00:00
macosx: Fix crash from array with incorrect types being assigned to dummy item mediaItems

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

- - - - -
4c1e8b7c by Claudio Cambra at 2025-07-20T06:11:34+00:00
macosx: Reintroduce VLCLibraryCollectionViewAudioGroupSupplementaryDetailView

This reverts commit 78a7672419049bc75c91993a85ef0466805fb2ef.

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

- - - - -
260bf96c by Claudio Cambra at 2025-07-20T06:11:34+00:00
macosx: Provide audio group supplementary detail view in favorites view

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

- - - - -
6dd6ea0f by Claudio Cambra at 2025-07-20T06:11:34+00:00
macosx: Use one method to check if section is an audio group section

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

- - - - -
78ae6a16 by Claudio Cambra at 2025-07-20T06:11:34+00:00
macosx: Fix crash on deselection of audio group in collection view for favorites view

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

- - - - -
b73fe9ec by Claudio Cambra at 2025-07-20T06:11:34+00:00
macosx: Present the media list supplementary detail view for albums

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

- - - - -


12 changed files:

- extras/package/macosx/VLC.xcodeproj/project.pbxproj
- modules/gui/macosx/Makefile.am
- + modules/gui/macosx/UI/VLCLibraryCollectionViewAudioGroupSupplementaryDetailView.xib
- modules/gui/macosx/library/VLCLibraryCollectionViewFlowLayout.m
- modules/gui/macosx/library/VLCLibraryDataTypes.h
- modules/gui/macosx/library/VLCLibraryDataTypes.m
- modules/gui/macosx/library/VLCLibraryMenuController.m
- modules/gui/macosx/library/VLCLibraryTableViewDelegate.m
- + modules/gui/macosx/library/audio-library/VLCLibraryCollectionViewAudioGroupSupplementaryDetailView.h
- + modules/gui/macosx/library/audio-library/VLCLibraryCollectionViewAudioGroupSupplementaryDetailView.m
- modules/gui/macosx/library/favorites-library/VLCLibraryFavoritesDataSource.m
- modules/gui/macosx/library/favorites-library/VLCLibraryFavoritesViewController.m


Changes:

=====================================
extras/package/macosx/VLC.xcodeproj/project.pbxproj
=====================================
@@ -116,6 +116,7 @@
 		536283F2291146BC00640C15 /* VLCLibraryCollectionViewMediaItemListSupplementaryDetailView.m in Sources */ = {isa = PBXBuildFile; fileRef = 536283E1291146BC00640C15 /* VLCLibraryCollectionViewMediaItemListSupplementaryDetailView.m */; };
 		536283F4291146BC00640C15 /* VLCLibraryCollectionViewMediaItemSupplementaryDetailView.m in Sources */ = {isa = PBXBuildFile; fileRef = 536283E3291146BC00640C15 /* VLCLibraryCollectionViewMediaItemSupplementaryDetailView.m */; };
 		536283F5291146BC00640C15 /* VLCLibraryCollectionViewSupplementaryDetailView.m in Sources */ = {isa = PBXBuildFile; fileRef = 536283E5291146BC00640C15 /* VLCLibraryCollectionViewSupplementaryDetailView.m */; };
+		536283F6291146BC00640C15 /* VLCLibraryCollectionViewAudioGroupSupplementaryDetailView.m in Sources */ = {isa = PBXBuildFile; fileRef = 536283E9291146BC00640C15 /* VLCLibraryCollectionViewAudioGroupSupplementaryDetailView.m */; };
 		536283F8291146BC00640C15 /* VLCLibrarySongTableCellView.m in Sources */ = {isa = PBXBuildFile; fileRef = 536283EC291146BC00640C15 /* VLCLibrarySongTableCellView.m */; };
 		536283F9291146BC00640C15 /* VLCLibraryCollectionViewFlowLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 536283EE291146BC00640C15 /* VLCLibraryCollectionViewFlowLayout.m */; };
 		53628402291147C500640C15 /* VLCBasicView.m in Sources */ = {isa = PBXBuildFile; fileRef = 536283FF291147C500640C15 /* VLCBasicView.m */; };
@@ -397,11 +398,14 @@
 		536283E5291146BC00640C15 /* VLCLibraryCollectionViewSupplementaryDetailView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VLCLibraryCollectionViewSupplementaryDetailView.m; sourceTree = "<group>"; };
 		536283E6291146BC00640C15 /* VLCLibraryCollectionViewSupplementaryDetailView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VLCLibraryCollectionViewSupplementaryDetailView.h; sourceTree = "<group>"; };
 		536283E8291146BC00640C15 /* VLCLibraryCollectionViewMediaItemListSupplementaryDetailView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VLCLibraryCollectionViewMediaItemListSupplementaryDetailView.h; sourceTree = "<group>"; };
+		536283E7291146BC00640C15 /* VLCLibraryCollectionViewAudioGroupSupplementaryDetailView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VLCLibraryCollectionViewAudioGroupSupplementaryDetailView.h; sourceTree = "<group>"; };
+		536283E9291146BC00640C15 /* VLCLibraryCollectionViewAudioGroupSupplementaryDetailView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VLCLibraryCollectionViewAudioGroupSupplementaryDetailView.m; sourceTree = "<group>"; };
 		536283EA291146BC00640C15 /* VLCLibraryCollectionViewMediaItemSupplementaryDetailView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VLCLibraryCollectionViewMediaItemSupplementaryDetailView.h; sourceTree = "<group>"; };
 		536283EC291146BC00640C15 /* VLCLibrarySongTableCellView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VLCLibrarySongTableCellView.m; sourceTree = "<group>"; };
 		536283ED291146BC00640C15 /* VLCLibraryCollectionViewFlowLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VLCLibraryCollectionViewFlowLayout.h; sourceTree = "<group>"; };
 		536283EE291146BC00640C15 /* VLCLibraryCollectionViewFlowLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VLCLibraryCollectionViewFlowLayout.m; sourceTree = "<group>"; };
 		536283FA2911476A00640C15 /* VLCLibrarySongTableCellView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = VLCLibrarySongTableCellView.xib; sourceTree = "<group>"; };
+		536283FB2911476A00640C15 /* VLCLibraryCollectionViewAudioGroupSupplementaryDetailView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = VLCLibraryCollectionViewAudioGroupSupplementaryDetailView.xib; sourceTree = "<group>"; };
 		536283FC2911476A00640C15 /* VLCLibraryCollectionViewMediaItemSupplementaryDetailView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = VLCLibraryCollectionViewMediaItemSupplementaryDetailView.xib; sourceTree = "<group>"; };
 		536283FD2911476A00640C15 /* VLCLibraryCollectionViewMediaItemListSupplementaryDetailView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = VLCLibraryCollectionViewMediaItemListSupplementaryDetailView.xib; sourceTree = "<group>"; };
 		536283FE291147C500640C15 /* VLCBasicView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VLCBasicView.h; sourceTree = "<group>"; };
@@ -1654,6 +1658,8 @@
 				53ED472529C78FE700795DB1 /* VLCLibraryAudioGroupTableViewDelegate.m */,
 				53ED472129C74D1F00795DB1 /* VLCLibraryAudioTableViewDelegate.h */,
 				53ED472229C74D1F00795DB1 /* VLCLibraryAudioTableViewDelegate.m */,
+				536283E7291146BC00640C15 /* VLCLibraryCollectionViewAudioGroupSupplementaryDetailView.h */,
+				536283E9291146BC00640C15 /* VLCLibraryCollectionViewAudioGroupSupplementaryDetailView.m */,
 				536283DD291146BC00640C15 /* VLCLibrarySongTableCellView.h */,
 				536283EC291146BC00640C15 /* VLCLibrarySongTableCellView.m */,
 				53B447C82939823E00857588 /* VLCLibrarySongsTableViewSongPlayingTableCellView.h */,
@@ -2169,6 +2175,7 @@
 				53BFB1E02A6A72160065EA7A /* VLCLibraryAudioGroupHeaderView.xib */,
 				53088E122AD6EADF00C21358 /* VLCLibraryCarouselViewItemView.xib */,
 				536283FD2911476A00640C15 /* VLCLibraryCollectionViewMediaItemListSupplementaryDetailView.xib */,
+				536283FB2911476A00640C15 /* VLCLibraryCollectionViewAudioGroupSupplementaryDetailView.xib */,
 				7D0F64052202047900FDB91F /* VLCLibraryCollectionViewItem.xib */,
 				536283FC2911476A00640C15 /* VLCLibraryCollectionViewMediaItemSupplementaryDetailView.xib */,
 				53B40FD42AA7618000C814E4 /* VLCLibraryHeroView.xib */,
@@ -2322,6 +2329,7 @@
 				7DFBDCAB2269E77F00B700A5 /* VLCLibraryModel.m in Sources */,
 				1CCC89012078A3D500E5626F /* Preferences.xib in Sources */,
 				7DC21A7422049A6600F98A02 /* VLCOpenInputMetadata.m in Sources */,
+				536283F6291146BC00640C15 /* VLCLibraryCollectionViewAudioGroupSupplementaryDetailView.m in Sources */,
 				1CCC89022078A3D500E5626F /* ResumeDialog.xib in Sources */,
 				531062162CE259290087F863 /* VLCLibraryHomeViewActionButtonCell.m in Sources */,
 				532572032C3D79D80068DEC3 /* VLCLibrarySegmentBookmarkedLocation.m in Sources */,


=====================================
modules/gui/macosx/Makefile.am
=====================================
@@ -287,6 +287,8 @@ libmacosx_plugin_la_SOURCES = \
 	gui/macosx/library/audio-library/VLCLibraryAudioTableViewDelegate.m \
 	gui/macosx/library/audio-library/VLCLibraryAudioViewController.h \
 	gui/macosx/library/audio-library/VLCLibraryAudioViewController.m \
+	gui/macosx/library/audio-library/VLCLibraryCollectionViewAudioGroupSupplementaryDetailView.h \
+	gui/macosx/library/audio-library/VLCLibraryCollectionViewAudioGroupSupplementaryDetailView.m \
 	gui/macosx/library/audio-library/VLCLibrarySongTableCellView.h \
 	gui/macosx/library/audio-library/VLCLibrarySongTableCellView.m \
 	gui/macosx/library/audio-library/VLCLibrarySongsTableViewSongPlayingTableCellView.h \
@@ -553,6 +555,7 @@ libmacosx_plugin_la_XIB_SOURCES = \
 	gui/macosx/UI/VLCLibraryCarouselViewItemView.xib \
 	gui/macosx/UI/VLCLibraryCollectionViewItem.xib \
 	gui/macosx/UI/VLCLibraryCollectionViewMediaItemListSupplementaryDetailView.xib \
+	gui/macosx/UI/VLCLibraryCollectionViewAudioGroupSupplementaryDetailView.xib \
 	gui/macosx/UI/VLCLibraryCollectionViewMediaItemSupplementaryDetailView.xib \
 	gui/macosx/UI/VLCLibraryHeroView.xib \
 	gui/macosx/UI/VLCLibraryHomeViewActionsView.xib \


=====================================
modules/gui/macosx/UI/VLCLibraryCollectionViewAudioGroupSupplementaryDetailView.xib
=====================================
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="20037" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
+    <dependencies>
+        <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="20037"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <customObject id="-2" userLabel="File's Owner" customClass="VLCLibraryCollectionViewAudioGroupSupplementaryDetailView"/>
+        <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
+        <customObject id="-3" userLabel="Application" customClass="NSObject"/>
+        <view id="HAc-or-XD8" customClass="VLCLibraryCollectionViewAudioGroupSupplementaryDetailView">
+            <rect key="frame" x="0.0" y="0.0" width="1071" height="322"/>
+            <autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
+            <subviews>
+                <stackView distribution="fill" orientation="vertical" alignment="leading" spacing="5" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="bw7-QB-Ssc">
+                    <rect key="frame" x="10" y="10" width="1051" height="282"/>
+                    <subviews>
+                        <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="nCe-dY-YMM">
+                            <rect key="frame" x="-2" y="203" width="178" height="79"/>
+                            <textFieldCell key="cell" lineBreakMode="truncatingTail" title="Audio group name" id="6RM-x8-Y4y">
+                                <font key="font" textStyle="title1" name=".SFNS-Regular"/>
+                                <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
+                                <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
+                            </textFieldCell>
+                        </textField>
+                        <scrollView borderType="none" autohidesScrollers="YES" horizontalLineScroll="19" horizontalPageScroll="10" verticalLineScroll="19" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" horizontalScrollElasticity="none" id="9ZS-oy-iP9" customClass="VLCSubScrollView">
+                            <rect key="frame" x="0.0" y="0.0" width="701" height="198"/>
+                            <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
+                            <clipView key="contentView" drawsBackground="NO" id="3V4-tX-owM">
+                                <rect key="frame" x="0.0" y="0.0" width="701" height="198"/>
+                                <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                                <subviews>
+                                    <tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" tableStyle="fullWidth" columnReordering="NO" columnResizing="NO" multipleSelection="NO" autosaveColumns="NO" typeSelect="NO" rowSizeStyle="automatic" viewBased="YES" id="eEJ-WA-0aM" customClass="VLCLibraryTableView">
+                                        <rect key="frame" x="0.0" y="0.0" width="701" height="188"/>
+                                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                                        <size key="intercellSpacing" width="3" height="2"/>
+                                        <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
+                                        <color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
+                                        <tableColumns>
+                                            <tableColumn width="689" minWidth="10" maxWidth="3.4028234663852886e+38" id="fqq-am-CS8">
+                                                <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left">
+                                                    <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
+                                                    <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                                </tableHeaderCell>
+                                                <textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" alignment="left" title="Text Cell" id="1js-Fu-KuW">
+                                                    <font key="font" metaFont="system"/>
+                                                    <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+                                                    <color key="backgroundColor" red="1" green="1" blue="1" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
+                                                </textFieldCell>
+                                                <tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
+                                            </tableColumn>
+                                        </tableColumns>
+                                    </tableView>
+                                </subviews>
+                                <nil key="backgroundColor"/>
+                            </clipView>
+                            <edgeInsets key="contentInsets" left="0.0" right="0.0" top="0.0" bottom="10"/>
+                            <scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="ZBY-pE-E7T">
+                                <rect key="frame" x="-100" y="-100" width="701" height="15"/>
+                                <autoresizingMask key="autoresizingMask"/>
+                            </scroller>
+                            <scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="WRE-VM-L7s">
+                                <rect key="frame" x="224" y="17" width="15" height="102"/>
+                                <autoresizingMask key="autoresizingMask"/>
+                            </scroller>
+                        </scrollView>
+                    </subviews>
+                    <visibilityPriorities>
+                        <integer value="1000"/>
+                        <integer value="1000"/>
+                    </visibilityPriorities>
+                    <customSpacing>
+                        <real value="3.4028234663852886e+38"/>
+                        <real value="3.4028234663852886e+38"/>
+                    </customSpacing>
+                </stackView>
+            </subviews>
+            <constraints>
+                <constraint firstAttribute="trailing" secondItem="bw7-QB-Ssc" secondAttribute="trailing" constant="10" id="8QK-wS-vnX"/>
+                <constraint firstItem="bw7-QB-Ssc" firstAttribute="leading" secondItem="HAc-or-XD8" secondAttribute="leading" constant="10" id="L0r-A5-7Xq"/>
+                <constraint firstAttribute="bottom" secondItem="bw7-QB-Ssc" secondAttribute="bottom" constant="10" id="eS3-iK-oGV"/>
+                <constraint firstItem="bw7-QB-Ssc" firstAttribute="top" secondItem="HAc-or-XD8" secondAttribute="top" constant="30" id="oWk-8b-f1e"/>
+            </constraints>
+            <connections>
+                <outlet property="audioGroupAlbumsTableView" destination="eEJ-WA-0aM" id="l8k-M9-a8e"/>
+                <outlet property="audioGroupNameTextField" destination="nCe-dY-YMM" id="h3l-p0-w3e"/>
+                <outlet property="contentViewBottomConstraint" destination="eS3-iK-oGV" id="T0p-C1-8jm"/>
+                <outlet property="contentViewLeftConstraint" destination="L0r-A5-7Xq" id="T0p-C1-a8j"/>
+                <outlet property="contentViewRightConstraint" destination="8QK-wS-vnX" id="T0p-C1-a7l"/>
+                <outlet property="contentViewTopConstraint" destination="oWk-8b-f1e" id="T0p-C1-1nv"/>
+                <outlet property="internalScrollView" destination="9ZS-oy-iP9" id="afa-6P-b12"/>
+                <outlet property="tableClipView" destination="3V4-tX-owM" id="t4b-1e-Cl1"/>
+                <outlet property="tableScrollView" destination="9ZS-oy-iP9" id="tab-L3-Scr"/>
+            </connections>
+            <point key="canvasLocation" x="-237.5" y="-284"/>
+        </view>
+    </objects>
+</document>


=====================================
modules/gui/macosx/library/VLCLibraryCollectionViewFlowLayout.m
=====================================
@@ -29,6 +29,7 @@
 
 #import "library/audio-library/VLCLibraryAudioDataSource.h"
 #import "library/audio-library/VLCLibraryAudioGroupDataSource.h"
+#import "library/audio-library/VLCLibraryCollectionViewAudioGroupSupplementaryDetailView.h"
 
 #pragma mark - Private data
 static const NSUInteger kAnimationSteps = 32;
@@ -312,10 +313,14 @@ static CVReturn detailViewAnimationCallback(CVDisplayLinkRef displayLink,
     BOOL isLibrarySupplementaryView = NO;
 
     if ([elementKind isEqualToString:VLCLibraryCollectionViewMediaItemListSupplementaryDetailViewKind] ||
-               [elementKind isEqualToString:VLCLibraryCollectionViewMediaItemSupplementaryDetailViewKind]) {
+        [elementKind isEqualToString:VLCLibraryCollectionViewMediaItemSupplementaryDetailViewKind]) {
 
         isLibrarySupplementaryView = YES;
         _animationType = self.scrollDirection == NSCollectionViewScrollDirectionVertical ? VLCExpandAnimationTypeVerticalMedium : VLCExpandAnimationTypeHorizontalMedium;
+    } else if ([elementKind isEqualToString:VLCLibraryCollectionViewAudioGroupSupplementaryDetailViewKind]) {
+
+        isLibrarySupplementaryView = YES;
+        _animationType = self.scrollDirection == NSCollectionViewScrollDirectionVertical ? VLCExpandAnimationTypeVerticalLarge : VLCExpandAnimationTypeHorizontalLarge;
     }
 
     if(isLibrarySupplementaryView) {
@@ -357,7 +362,8 @@ static CVReturn detailViewAnimationCallback(CVDisplayLinkRef displayLink,
 - (NSSet<NSIndexPath *> *)indexPathsToDeleteForSupplementaryViewOfKind:(NSString *)elementKind
 {
     if ([elementKind isEqualToString:VLCLibraryCollectionViewMediaItemListSupplementaryDetailViewKind] ||
-        [elementKind isEqualToString:VLCLibraryCollectionViewMediaItemSupplementaryDetailViewKind]) {
+        [elementKind isEqualToString:VLCLibraryCollectionViewMediaItemSupplementaryDetailViewKind] ||
+        [elementKind isEqualToString:VLCLibraryCollectionViewAudioGroupSupplementaryDetailViewKind]) {
 
         return [self.collectionView indexPathsForVisibleSupplementaryElementsOfKind:elementKind];
     }


=====================================
modules/gui/macosx/library/VLCLibraryDataTypes.h
=====================================
@@ -138,6 +138,10 @@ typedef NS_ENUM(NSUInteger, VLCMediaLibraryParentGroupType) {
 @property (readonly) BOOL secondaryActionableDetail;
 @property (readonly) id<VLCMediaLibraryItemProtocol> secondaryActionableDetailLibraryItem;
 @property (readonly) NSArray<NSString *> *labels;
+ at property (readonly) BOOL favorited;
+
+- (int)setFavorite:(BOOL)favorite;
+- (int)toggleFavorite;
 
 - (void)iterateMediaItemsWithBlock:(void (^)(VLCMediaLibraryMediaItem*))mediaItemBlock;
 
@@ -306,8 +310,6 @@ typedef NS_ENUM(NSUInteger, VLCMediaLibraryParentGroupType) {
 @property (readonly) float progress;
 @property (readonly) NSString *title;
 
- at property (readonly) BOOL favorited;
-
 @property (readonly, nullable) VLCMediaLibraryShowEpisode *showEpisode;
 @property (readonly, nullable) VLCMediaLibraryMovie *movie;
 
@@ -335,9 +337,6 @@ typedef NS_ENUM(NSUInteger, VLCMediaLibraryParentGroupType) {
 @property (readonly) int trackNumber;
 @property (readonly) int discNumber;
 
-- (int)setFavorite:(BOOL)favorite;
-- (int)toggleFavorite;
-
 @end
 
 @interface VLCMediaLibraryEntryPoint : NSObject


=====================================
modules/gui/macosx/library/VLCLibraryDataTypes.m
=====================================
@@ -44,6 +44,7 @@ NSString *VLCMediaLibraryMediaItemLibraryID = @"VLCMediaLibraryMediaItemLibraryI
 typedef vlc_ml_media_list_t* (*library_mediaitem_list_fetch_f)(vlc_medialibrary_t*, const vlc_ml_query_params_t*, int64_t);
 typedef vlc_ml_album_list_t* (*library_album_list_fetch_f)(vlc_medialibrary_t*, const vlc_ml_query_params_t*, int64_t);
 typedef vlc_ml_artist_list_t* (*library_artist_list_fetch_f)(vlc_medialibrary_t*, const vlc_ml_query_params_t*, int64_t);
+typedef int (*library_item_set_favorite_f)(vlc_medialibrary_t*, int64_t, bool);
 
 static vlc_medialibrary_t *getMediaLibrary(void)
 {
@@ -134,6 +135,15 @@ static NSArray<NSString *> *labelsForMediaLibraryItem(const int64_t libraryID) {
     return labels.copy;
 }
 
+static int setFavoriteForLibraryItem(library_item_set_favorite_f setFavoriteFunction, const int64_t itemId, const BOOL favorite)
+{
+    vlc_medialibrary_t * const p_mediaLibrary = getMediaLibrary();
+    if (!p_mediaLibrary) {
+        return VLC_EGENERIC;
+    }
+    return setFavoriteFunction(p_mediaLibrary, itemId, favorite);
+}
+
 static NSString *genreArrayDisplayString(NSArray<VLCMediaLibraryGenre *> * const genres)
 {
     const NSUInteger genreCount = genres.count;
@@ -346,6 +356,42 @@ static NSString *genreArrayDisplayString(NSArray<VLCMediaLibraryGenre *> * const
     return self.internalLabels;
 }
 
+- (BOOL)favorited
+{
+    __block BOOL allFavorited = YES;
+    __block BOOL hasItems = NO;
+    
+    [self iterateMediaItemsWithBlock:^(VLCMediaLibraryMediaItem * _Nonnull mediaItem) {
+        hasItems = YES;
+        if (!mediaItem.favorited) {
+            allFavorited = NO;
+        }
+    }];
+    
+    return hasItems && allFavorited;
+}
+
+- (int)setFavorite:(BOOL)favorite
+{
+    __block int lastResult = VLC_SUCCESS;
+    __block BOOL hasItems = NO;
+    
+    [self iterateMediaItemsWithBlock:^(VLCMediaLibraryMediaItem * _Nonnull mediaItem) {
+        hasItems = YES;
+        const int result = [mediaItem setFavorite:favorite];
+        if (result != VLC_SUCCESS) {
+            lastResult = result;
+        }
+    }];
+    
+    return hasItems ? lastResult : VLC_EGENERIC;
+}
+
+- (int)toggleFavorite
+{
+    return [self setFavorite:!self.favorited];
+}
+
 @end
 
 @interface VLCAbstractMediaLibraryAudioGroup ()
@@ -419,6 +465,7 @@ static NSString *genreArrayDisplayString(NSArray<VLCMediaLibraryGenre *> * const
 @implementation VLCMediaLibraryArtist
 
 @synthesize numberOfTracks = _numberOfTracks;
+ at synthesize favorited = _favorited;
 
 + (nullable instancetype)artistWithID:(int64_t)artistID
 {
@@ -449,6 +496,7 @@ static NSString *genreArrayDisplayString(NSArray<VLCMediaLibraryGenre *> * const
         _musicBrainzID = toNSStr(p_artist->psz_mb_id);
         _numberOfAlbums = p_artist->i_nb_album;
         _numberOfTracks = p_artist->i_nb_tracks;
+        _favorited = p_artist->b_is_favorite;
     }
     return self;
 }
@@ -526,6 +574,14 @@ static NSString *genreArrayDisplayString(NSArray<VLCMediaLibraryGenre *> * const
     }
 }
 
+- (int)setFavorite:(BOOL)favorite
+{
+    const int res = setFavoriteForLibraryItem(vlc_ml_artist_set_favorite, self.libraryID, favorite);
+    if (res == VLC_SUCCESS)
+        _favorited = favorite;
+    return res;
+}
+
 @end
 
 @interface VLCMediaLibraryAlbum ()
@@ -538,6 +594,7 @@ static NSString *genreArrayDisplayString(NSArray<VLCMediaLibraryGenre *> * const
 
 @synthesize numberOfTracks = _numberOfTracks;
 @synthesize primaryActionableDetailLibraryItem = _primaryActionableDetailLibraryItem;
+ at synthesize favorited = _favorited;
 
 + (nullable instancetype)albumWithID:(int64_t)albumID
 {
@@ -570,6 +627,7 @@ static NSString *genreArrayDisplayString(NSArray<VLCMediaLibraryGenre *> * const
         _numberOfTracks = p_album->i_nb_tracks;
         _duration = p_album->i_duration;
         _year = p_album->i_year;
+        _favorited = p_album->b_is_favorite;
     }
     return self;
 }
@@ -644,11 +702,20 @@ static NSString *genreArrayDisplayString(NSArray<VLCMediaLibraryGenre *> * const
     }
 }
 
+- (int)setFavorite:(BOOL)favorite
+{
+    const int res = setFavoriteForLibraryItem(vlc_ml_album_set_favorite, self.libraryID, favorite);
+    if (res == VLC_SUCCESS)
+        _favorited = favorite;
+    return res;
+}
+
 @end
 
 @implementation VLCMediaLibraryGenre
 
 @synthesize numberOfTracks = _numberOfTracks;
+ at synthesize favorited = _favorited;
 
 - (instancetype)initWithGenre:(struct vlc_ml_genre_t *)p_genre
 {
@@ -662,6 +729,7 @@ static NSString *genreArrayDisplayString(NSArray<VLCMediaLibraryGenre *> * const
 
         _name = toNSStr(p_genre->psz_name);
         _numberOfTracks = p_genre->i_nb_tracks;
+        _favorited = p_genre->b_is_favorite;
     }
     return self;
 }
@@ -752,6 +820,14 @@ static NSString *genreArrayDisplayString(NSArray<VLCMediaLibraryGenre *> * const
     }
 }
 
+- (int)setFavorite:(BOOL)favorite
+{
+    const int res = setFavoriteForLibraryItem(vlc_ml_genre_set_favorite, self.libraryID, favorite);
+    if (res == VLC_SUCCESS)
+        _favorited = favorite;
+    return res;
+}
+
 @end
 
 @interface VLCMediaLibraryGroup ()
@@ -839,6 +915,8 @@ static NSString *genreArrayDisplayString(NSArray<VLCMediaLibraryGenre *> * const
 
 @implementation VLCMediaLibraryPlaylist
 
+ at synthesize favorited = _favorited;
+
 + (instancetype)playlistForLibraryID:(int64_t)libraryID
 {
     vlc_medialibrary_t * const p_mediaLibrary = getMediaLibrary();
@@ -882,6 +960,7 @@ static NSString *genreArrayDisplayString(NSArray<VLCMediaLibraryGenre *> * const
         _numberDurationUnknown = p_playlist->i_nb_duration_unknown;
 
         _readOnly = p_playlist->b_is_read_only;
+        _favorited = p_playlist->b_is_favorite;
     }
     return self;
 }
@@ -945,6 +1024,14 @@ static NSString *genreArrayDisplayString(NSArray<VLCMediaLibraryGenre *> * const
     }
 }
 
+- (int)setFavorite:(BOOL)favorite
+{
+    const int res = setFavoriteForLibraryItem(vlc_ml_playlist_set_favorite, self.libraryID, favorite);
+    if (res == VLC_SUCCESS)
+        _favorited = favorite;
+    return res;
+}
+
 @end
 
 @interface VLCMediaLibraryMediaItem ()
@@ -965,6 +1052,7 @@ static NSString *genreArrayDisplayString(NSArray<VLCMediaLibraryGenre *> * const
 @synthesize secondaryActionableDetail = _secondaryActionableDetail;
 @synthesize primaryActionableDetailLibraryItem = _primaryActionableDetailLibraryItem;
 @synthesize secondaryActionableDetailLibraryItem = _secondaryActionableDetailLibraryItem;
+ at synthesize favorited = _favorited;
 
 #pragma mark - initialization
 
@@ -1564,14 +1652,12 @@ static NSString *genreArrayDisplayString(NSArray<VLCMediaLibraryGenre *> * const
 
 - (int)setFavorite:(BOOL)favorite
 {
-    const int64_t mediaItemId = self.libraryID;
-    vlc_medialibrary_t * const p_ml = vlc_ml_instance_get(getIntf());
-    const int result = vlc_ml_media_set_favorite(p_ml, mediaItemId, favorite);
-    if (result == VLC_SUCCESS)
+    const int res = setFavoriteForLibraryItem(vlc_ml_media_set_favorite, self.libraryID, favorite);
+    if (res == VLC_SUCCESS)
         _favorited = favorite;
     else
-        NSLog(@"Unable to set favorite status of media item: %lli", mediaItemId);
-    return result;
+        NSLog(@"Unable to set favorite status of media item: %lli", self.libraryID);
+    return res;
 }
 
 - (int)toggleFavorite
@@ -1701,6 +1787,7 @@ static NSString *genreArrayDisplayString(NSArray<VLCMediaLibraryGenre *> * const
 @synthesize secondaryActionableDetail = _secondaryActionableDetail;
 @synthesize secondaryActionableDetailLibraryItem = _secondaryActionableDetailLibraryItem;
 @synthesize labels = _labels;
+ at synthesize favorited = _favorited;
 
 - (instancetype)initWithDisplayString:(NSString *)displayString
               withPrimaryDetailString:(nullable NSString *)primaryDetailString


=====================================
modules/gui/macosx/library/VLCLibraryMenuController.m
=====================================
@@ -164,16 +164,12 @@
         }
         [self menuItems:_recentsMediaItemRequiringMenuItems setHidden:anyNonRecent];
         
-        __block BOOL anyUnfavorited = NO;
+        BOOL anyUnfavorited = NO;
         for (VLCLibraryRepresentedItem * const item in self.representedItems) {
-            [item.item iterateMediaItemsWithBlock:^(VLCMediaLibraryMediaItem * _Nonnull const mediaItem) {
-                if (!mediaItem.favorited) {
-                    anyUnfavorited = YES;
-                    return;
-                }
-            }];
-            if (anyUnfavorited)
+            if (!item.item.favorited) {
+                anyUnfavorited = YES;
                 break;
+            }
         }
         self.favoriteItem.title = anyUnfavorited ? _NS("Add to Favorites") : _NS("Remove from Favorites");
         self.favoriteItem.action = anyUnfavorited ? @selector(addFavorite:) : @selector(removeFavorite:);
@@ -319,9 +315,7 @@
 - (void)setItemsFavorite:(BOOL)favorite
 {
     for (VLCLibraryRepresentedItem * const item in self.representedItems) {
-        [item.item iterateMediaItemsWithBlock:^(VLCMediaLibraryMediaItem * _Nonnull const mediaItem) {
-            [mediaItem setFavorite:favorite];
-        }];
+        [item.item setFavorite:favorite];
     }
 }
 


=====================================
modules/gui/macosx/library/VLCLibraryTableViewDelegate.m
=====================================
@@ -103,27 +103,18 @@
         appendToPlayQueueAction.backgroundColor = NSColor.VLCAccentColor;
         return @[appendToPlayQueueAction];
     } else if (edge == NSTableRowActionEdgeTrailing) {
-        __block BOOL anyUnfavorited = NO;
-        for (VLCMediaLibraryMediaItem * const item in libraryItem.mediaItems) {
-            if (!item.favorited) {
-                anyUnfavorited = YES;
-                break;
-            }
-        }
+        const BOOL isFavorited = libraryItem.favorited;
         NSString * const displayString =
-            anyUnfavorited ? _NS("Add to Favorites") : _NS("Remove from Favorites");
+            isFavorited ? _NS("Remove from Favorites") : _NS("Add to Favorites");
 
         NSTableViewRowAction * const favoriteAction =
             [NSTableViewRowAction rowActionWithStyle:NSTableViewRowActionStyleRegular
                                                title:displayString
                                              handler:^(NSTableViewRowAction *action, NSInteger r) {
-            [libraryItem iterateMediaItemsWithBlock:^(VLCMediaLibraryMediaItem *const mediaItem) {
-                const BOOL setFavorited = !mediaItem.favorited;
-                [mediaItem setFavorite:setFavorited];
-            }];
+            [libraryItem setFavorite:!isFavorited];
         }];
         favoriteAction.backgroundColor =
-            anyUnfavorited ? NSColor.systemRedColor : NSColor.systemBlueColor;
+            isFavorited ? NSColor.systemBlueColor : NSColor.systemRedColor;
         return @[favoriteAction];
     }
     return @[];


=====================================
modules/gui/macosx/library/audio-library/VLCLibraryCollectionViewAudioGroupSupplementaryDetailView.h
=====================================
@@ -0,0 +1,43 @@
+/*****************************************************************************
+ * VLCLibraryCollectionViewAudioGroupSupplementaryDetailView.h: MacOS X interface module
+ *****************************************************************************
+ * Copyright (C) 2022 VLC authors and VideoLAN
+ *
+ * Authors: Claudio Cambra <claudio.cambra at gmail.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/VLCLibraryCollectionViewSupplementaryDetailView.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+ at class VLCImageView;
+
+extern NSString *const VLCLibraryCollectionViewAudioGroupSupplementaryDetailViewIdentifier;
+extern NSCollectionViewSupplementaryElementKind const VLCLibraryCollectionViewAudioGroupSupplementaryDetailViewKind;
+
+ at interface VLCLibraryCollectionViewAudioGroupSupplementaryDetailView : VLCLibraryCollectionViewSupplementaryDetailView
+
+ at property (readwrite, weak) IBOutlet NSTextField *audioGroupNameTextField;
+ at property (readwrite, weak) IBOutlet NSTableView *audioGroupAlbumsTableView;
+ at property (readwrite, weak) IBOutlet NSClipView *tableClipView;
+ at property (readwrite, weak) IBOutlet NSScrollView *tableScrollView;
+
+ at end
+
+NS_ASSUME_NONNULL_END


=====================================
modules/gui/macosx/library/audio-library/VLCLibraryCollectionViewAudioGroupSupplementaryDetailView.m
=====================================
@@ -0,0 +1,100 @@
+/*****************************************************************************
+ * VLCLibraryCollectionViewAudioGroupSupplementaryDetailView.m: MacOS X interface module
+ *****************************************************************************
+ * Copyright (C) 2022 VLC authors and VideoLAN
+ *
+ * Authors: Claudio Cambra <claudio.cambra at gmail.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 "VLCLibraryCollectionViewAudioGroupSupplementaryDetailView.h"
+
+#import "extensions/NSFont+VLCAdditions.h"
+
+#import "library/VLCLibraryDataTypes.h"
+#import "library/VLCLibraryModel.h"
+#import "library/VLCLibraryRepresentedItem.h"
+
+#import "library/audio-library/VLCLibraryAudioGroupDataSource.h"
+#import "library/audio-library/VLCLibraryAudioGroupTableViewDelegate.h"
+
+NSString *const VLCLibraryCollectionViewAudioGroupSupplementaryDetailViewIdentifier = @"VLCLibraryCollectionViewAudioGroupSupplementaryDetailViewIdentifier";
+NSCollectionViewSupplementaryElementKind const VLCLibraryCollectionViewAudioGroupSupplementaryDetailViewKind = @"VLCLibraryCollectionViewAudioGroupSupplementaryDetailViewIdentifier";
+
+ at interface VLCLibraryCollectionViewAudioGroupSupplementaryDetailView ()
+{
+    VLCLibraryAudioGroupDataSource *_audioGroupAlbumsDataSource;
+    VLCLibraryAudioGroupTableViewDelegate *_audioGroupAlbumsTableViewDelegate;
+}
+
+ at end
+
+ at implementation VLCLibraryCollectionViewAudioGroupSupplementaryDetailView
+
+- (void)awakeFromNib
+{
+    _audioGroupAlbumsDataSource = [[VLCLibraryAudioGroupDataSource alloc] init];
+    _audioGroupAlbumsDataSource.tableViews = @[_audioGroupAlbumsTableView];
+
+    _audioGroupAlbumsTableViewDelegate = [[VLCLibraryAudioGroupTableViewDelegate alloc] init];
+
+    _audioGroupAlbumsTableView.dataSource = _audioGroupAlbumsDataSource;
+    _audioGroupAlbumsTableView.delegate = _audioGroupAlbumsTableViewDelegate;
+
+    _audioGroupNameTextField.font = NSFont.VLCLibrarySubsectionHeaderFont;
+
+    NSNotificationCenter * const notificationCenter = NSNotificationCenter.defaultCenter;
+    [notificationCenter addObserver:self
+                           selector:@selector(handleAudioGroupUpdated:)
+                               name:VLCLibraryModelAlbumUpdated
+                             object:nil];
+    [notificationCenter addObserver:self
+                           selector:@selector(handleAudioGroupUpdated:)
+                               name:VLCLibraryModelArtistUpdated
+                             object:nil];
+    [notificationCenter addObserver:self
+                           selector:@selector(handleAudioGroupUpdated:)
+                               name:VLCLibraryModelGenreUpdated
+                             object:nil];
+}
+
+- (void)handleAudioGroupUpdated:(NSNotification *)notification
+{
+    NSParameterAssert(notification);
+
+    if (self.representedItem == nil ||
+        notification.object == nil ||
+        ![notification.object conformsToProtocol:@protocol(VLCMediaLibraryAudioGroupProtocol)]) {
+
+        return;
+    }
+
+    const id<VLCMediaLibraryAudioGroupProtocol> audioGroup = (id<VLCMediaLibraryAudioGroupProtocol>)notification.object;
+    VLCLibraryRepresentedItem * const representedItem = [[VLCLibraryRepresentedItem alloc] initWithItem:audioGroup parentType:self.representedItem.parentType];
+    self.representedItem = representedItem;
+}
+
+- (void)updateRepresentation
+{
+    NSAssert(self.representedItem != nil, @"no media item assigned for collection view item", nil);
+    const id<VLCMediaLibraryAudioGroupProtocol> audioGroup = (id<VLCMediaLibraryAudioGroupProtocol>)self.representedItem.item;
+    NSAssert(audioGroup != nil, @"audio group should not be nil!");
+
+    _audioGroupNameTextField.stringValue = audioGroup.displayString;
+    _audioGroupAlbumsDataSource.representedAudioGroup = audioGroup;
+}
+
+ at end


=====================================
modules/gui/macosx/library/favorites-library/VLCLibraryFavoritesDataSource.m
=====================================
@@ -26,10 +26,12 @@
 #import "library/VLCLibraryCollectionViewItem.h"
 #import "library/VLCLibraryCollectionViewMediaItemSupplementaryDetailView.h"
 #import "library/VLCLibraryCollectionViewSupplementaryElementView.h"
+#import "library/VLCLibraryCollectionViewMediaItemListSupplementaryDetailView.h"
 #import "library/VLCLibraryModel.h"
 #import "library/VLCLibraryDataTypes.h"
 #import "library/VLCLibraryRepresentedItem.h"
 #import "library/VLCLibraryTableCellView.h"
+#import "library/audio-library/VLCLibraryCollectionViewAudioGroupSupplementaryDetailView.h"
 
 #import "views/VLCImageView.h"
 
@@ -128,6 +130,19 @@ NSString * const VLCLibraryFavoritesDataSourceDisplayedCollectionChangedNotifica
     return (VLCLibraryFavoritesSection)[_visibleSectionMapping[visibleIndex] integerValue];
 }
 
+- (BOOL)isAudioGroupSection:(VLCLibraryFavoritesSection)section
+{
+    // Only artists and genres show the audio group view (list of albums)
+    return section == VLCLibraryFavoritesSectionArtists ||
+           section == VLCLibraryFavoritesSectionGenres;
+}
+
+- (BOOL)isMediaListSection:(VLCLibraryFavoritesSection)section
+{
+    // Albums show the media list view (list of tracks)
+    return section == VLCLibraryFavoritesSectionAlbums;
+}
+
 - (NSInteger)visibleIndexForSection:(VLCLibraryFavoritesSection)section
 {
     NSNumber * const sectionNumber = @(section);
@@ -159,8 +174,26 @@ NSString * const VLCLibraryFavoritesDataSourceDisplayedCollectionChangedNotifica
 
 - (id<VLCMediaLibraryItemProtocol>)createGroupDescriptorForSection:(VLCLibraryFavoritesSection)section
 {
+    NSArray * const sectionArray = [self arrayForSection:section];
+    
+    // For video and audio media sections, the array already contains VLCMediaLibraryMediaItem objects
+    if (section == VLCLibraryFavoritesSectionVideoMedia || 
+        section == VLCLibraryFavoritesSectionAudioMedia) {
+        return [[VLCMediaLibraryDummyItem alloc] initWithDisplayString:[self titleForSection:section]
+                                                        withMediaItems:sectionArray];
+    }
+    
+    // For albums, artists, and genres, we need to extract media items from each item
+    NSMutableArray<VLCMediaLibraryMediaItem *> * const mediaItems = [NSMutableArray array];
+    for (id<VLCMediaLibraryItemProtocol> item in sectionArray) {
+        NSArray<VLCMediaLibraryMediaItem *> * const itemMediaItems = item.mediaItems;
+        if (itemMediaItems) {
+            [mediaItems addObjectsFromArray:itemMediaItems];
+        }
+    }
+    
     return [[VLCMediaLibraryDummyItem alloc] initWithDisplayString:[self titleForSection:section]
-                                                    withMediaItems:[self arrayForSection:section]];
+                                                    withMediaItems:[mediaItems copy]];
 }
 
 #pragma mark - Notification handlers
@@ -370,6 +403,19 @@ viewForSupplementaryElementOfKind:(NSCollectionViewSupplementaryElementKind)kind
         return sectionHeadingView;
 
     } else if ([kind isEqualToString:VLCLibraryCollectionViewMediaItemSupplementaryDetailViewKind]) {
+        const VLCLibraryFavoritesSection section = [self sectionForVisibleIndex:indexPath.section];
+        if ([self isAudioGroupSection:section]) {
+            // Redirect to audio group supplementary view
+            return [self collectionView:collectionView 
+                viewForSupplementaryElementOfKind:VLCLibraryCollectionViewAudioGroupSupplementaryDetailViewKind 
+                               atIndexPath:indexPath];
+        } else if ([self isMediaListSection:section]) {
+            // Redirect to media list supplementary view
+            return [self collectionView:collectionView 
+                viewForSupplementaryElementOfKind:VLCLibraryCollectionViewMediaItemListSupplementaryDetailViewKind 
+                               atIndexPath:indexPath];
+        }
+        
         VLCLibraryCollectionViewMediaItemSupplementaryDetailView * const mediaItemSupplementaryDetailView = 
             [collectionView makeSupplementaryViewOfKind:kind 
                                          withIdentifier:VLCLibraryCollectionViewMediaItemSupplementaryDetailViewKind 
@@ -381,6 +427,34 @@ viewForSupplementaryElementOfKind:(NSCollectionViewSupplementaryElementKind)kind
         mediaItemSupplementaryDetailView.representedItem = representedItem;
         mediaItemSupplementaryDetailView.selectedItem = [collectionView itemAtIndexPath:indexPath];
         return mediaItemSupplementaryDetailView;
+    } else if ([kind isEqualToString:VLCLibraryCollectionViewAudioGroupSupplementaryDetailViewKind]) {
+        VLCLibraryCollectionViewAudioGroupSupplementaryDetailView * const audioGroupSupplementaryDetailView = 
+            [collectionView makeSupplementaryViewOfKind:kind 
+                                         withIdentifier:VLCLibraryCollectionViewAudioGroupSupplementaryDetailViewIdentifier 
+                                           forIndexPath:indexPath];
+        
+        const id<VLCMediaLibraryItemProtocol> item = [self libraryItemAtIndexPath:indexPath forCollectionView:collectionView];
+        const VLCLibraryFavoritesSection section = [self sectionForVisibleIndex:indexPath.section];
+        const VLCMediaLibraryParentGroupType parentType = [self parentTypeForSection:section];
+        VLCLibraryRepresentedItem * const representedItem = [[VLCLibraryRepresentedItem alloc] initWithItem:item parentType:parentType];
+
+        audioGroupSupplementaryDetailView.representedItem = representedItem;
+        audioGroupSupplementaryDetailView.selectedItem = [collectionView itemAtIndexPath:indexPath];
+        return audioGroupSupplementaryDetailView;
+    } else if ([kind isEqualToString:VLCLibraryCollectionViewMediaItemListSupplementaryDetailViewKind]) {
+        VLCLibraryCollectionViewMediaItemListSupplementaryDetailView * const mediaListSupplementaryDetailView = 
+            [collectionView makeSupplementaryViewOfKind:kind 
+                                         withIdentifier:VLCLibraryCollectionViewMediaItemListSupplementaryDetailViewIdentifier 
+                                           forIndexPath:indexPath];
+        
+        const id<VLCMediaLibraryItemProtocol> item = [self libraryItemAtIndexPath:indexPath forCollectionView:collectionView];
+        const VLCLibraryFavoritesSection section = [self sectionForVisibleIndex:indexPath.section];
+        const VLCMediaLibraryParentGroupType parentType = [self parentTypeForSection:section];
+        VLCLibraryRepresentedItem * const representedItem = [[VLCLibraryRepresentedItem alloc] initWithItem:item parentType:parentType];
+
+        mediaListSupplementaryDetailView.representedItem = representedItem;
+        mediaListSupplementaryDetailView.selectedItem = [collectionView itemAtIndexPath:indexPath];
+        return mediaListSupplementaryDetailView;
     }
 
     return nil;
@@ -444,6 +518,17 @@ viewForSupplementaryElementOfKind:(NSCollectionViewSupplementaryElementKind)kind
 
 - (NSString *)supplementaryDetailViewKind
 {
+    if (self.collectionView.selectionIndexPaths.count > 0) {
+        NSIndexPath * const firstIndexPath = self.collectionView.selectionIndexPaths.anyObject;
+        const VLCLibraryFavoritesSection section = [self sectionForVisibleIndex:firstIndexPath.section];
+        
+        if ([self isAudioGroupSection:section]) {
+            return VLCLibraryCollectionViewAudioGroupSupplementaryDetailViewKind;
+        } else if ([self isMediaListSection:section]) {
+            return VLCLibraryCollectionViewMediaItemListSupplementaryDetailViewKind;
+        }
+    }
+    
     return VLCLibraryCollectionViewMediaItemSupplementaryDetailViewKind;
 }
 


=====================================
modules/gui/macosx/library/favorites-library/VLCLibraryFavoritesViewController.m
=====================================
@@ -28,6 +28,7 @@
 #import "library/VLCLibraryCollectionViewFlowLayout.h"
 #import "library/VLCLibraryCollectionViewItem.h"
 #import "library/VLCLibraryCollectionViewMediaItemSupplementaryDetailView.h"
+#import "library/VLCLibraryCollectionViewMediaItemListSupplementaryDetailView.h"
 #import "library/VLCLibraryCollectionViewSupplementaryElementView.h"
 #import "library/VLCLibraryController.h"
 #import "library/VLCLibraryModel.h"
@@ -39,6 +40,7 @@
 #import "library/VLCLibraryWindow.h"
 #import "library/VLCLibraryWindowPersistentPreferences.h"
 #import "library/favorites-library/VLCLibraryFavoritesDataSource.h"
+#import "library/audio-library/VLCLibraryCollectionViewAudioGroupSupplementaryDetailView.h"
 #import "main/VLCMain.h"
 
 @interface VLCLibraryFavoritesViewController ()
@@ -164,6 +166,24 @@
     [collectionView registerNib:mediaItemSupplementaryDetailViewNib
      forSupplementaryViewOfKind:VLCLibraryCollectionViewMediaItemSupplementaryDetailViewKind
                  withIdentifier:VLCLibraryCollectionViewMediaItemSupplementaryDetailViewIdentifier];
+    
+    NSString * const audioGroupSupplementaryDetailViewString =
+        NSStringFromClass(VLCLibraryCollectionViewAudioGroupSupplementaryDetailView.class);
+    NSNib * const audioGroupSupplementaryDetailViewNib =
+        [[NSNib alloc] initWithNibNamed:audioGroupSupplementaryDetailViewString bundle:nil];
+    
+    [collectionView registerNib:audioGroupSupplementaryDetailViewNib
+     forSupplementaryViewOfKind:VLCLibraryCollectionViewAudioGroupSupplementaryDetailViewKind
+                 withIdentifier:VLCLibraryCollectionViewAudioGroupSupplementaryDetailViewIdentifier];
+    
+    NSString * const mediaListSupplementaryDetailViewString =
+        NSStringFromClass(VLCLibraryCollectionViewMediaItemListSupplementaryDetailView.class);
+    NSNib * const mediaListSupplementaryDetailViewNib =
+        [[NSNib alloc] initWithNibNamed:mediaListSupplementaryDetailViewString bundle:nil];
+    
+    [collectionView registerNib:mediaListSupplementaryDetailViewNib
+     forSupplementaryViewOfKind:VLCLibraryCollectionViewMediaItemListSupplementaryDetailViewKind
+                 withIdentifier:VLCLibraryCollectionViewMediaItemListSupplementaryDetailViewIdentifier];
 }
 
 - (void)setupFavoritesDataSource



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/df581a1ed37ad82282331fa5a64bab59c4d6c4a0...b73fe9ec098c0a2e8a6ffaafe9033723b7c5c5de

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/df581a1ed37ad82282331fa5a64bab59c4d6c4a0...b73fe9ec098c0a2e8a6ffaafe9033723b7c5c5de
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