[vlc-commits] [Git][videolan/vlc][master] macosx: Add expandable detail view to the album collection view

Felix Paul Kühne (@fkuehne) gitlab at videolan.org
Tue Jul 19 19:44:18 UTC 2022



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


Commits:
53c0bfa2 by Claudio Cambra at 2022-07-19T21:05:12+02:00
macosx: Add expandable detail view to the album collection view

Signed-off-by: Claudio Cambra <claudio.cambra at gmail.com>

- - - - -


12 changed files:

- modules/gui/macosx/Makefile.am
- + modules/gui/macosx/UI/VLCLibraryCollectionViewAlbumSupplementaryDetailView.xib
- modules/gui/macosx/library/VLCLibraryAlbumTableCellView.h
- modules/gui/macosx/library/VLCLibraryAlbumTableCellView.m
- + modules/gui/macosx/library/VLCLibraryAlbumTracksDataSource.h
- + modules/gui/macosx/library/VLCLibraryAlbumTracksDataSource.m
- modules/gui/macosx/library/VLCLibraryAudioDataSource.m
- + modules/gui/macosx/library/VLCLibraryCollectionViewAlbumSupplementaryDetailView.h
- + modules/gui/macosx/library/VLCLibraryCollectionViewAlbumSupplementaryDetailView.m
- + modules/gui/macosx/library/VLCLibraryCollectionViewFlowLayout.h
- + modules/gui/macosx/library/VLCLibraryCollectionViewFlowLayout.m
- modules/gui/macosx/library/VLCLibraryWindow.m


Changes:

=====================================
modules/gui/macosx/Makefile.am
=====================================
@@ -58,10 +58,16 @@ libmacosx_plugin_la_SOURCES = \
 	gui/macosx/library/VLCInputItem.m \
 	gui/macosx/library/VLCLibraryAlbumTableCellView.h \
 	gui/macosx/library/VLCLibraryAlbumTableCellView.m \
+	gui/macosx/library/VLCLibraryAlbumTracksDataSource.h \
+	gui/macosx/library/VLCLibraryAlbumTracksDataSource.m \
 	gui/macosx/library/VLCLibraryAudioDataSource.h \
 	gui/macosx/library/VLCLibraryAudioDataSource.m \
+	gui/macosx/library/VLCLibraryCollectionViewFlowLayout.h \
+	gui/macosx/library/VLCLibraryCollectionViewFlowLayout.m \
 	gui/macosx/library/VLCLibraryCollectionViewItem.h \
 	gui/macosx/library/VLCLibraryCollectionViewItem.m \
+	gui/macosx/library/VLCLibraryCollectionViewAlbumSupplementaryDetailView.h \
+	gui/macosx/library/VLCLibraryCollectionViewAlbumSupplementaryDetailView.m \
 	gui/macosx/library/VLCLibraryCollectionViewSupplementaryElementView.h \
 	gui/macosx/library/VLCLibraryCollectionViewSupplementaryElementView.m \
 	gui/macosx/library/VLCLibraryController.h \
@@ -297,6 +303,7 @@ libmacosx_plugin_la_XIB_SOURCES = \
 	gui/macosx/UI/VLCLibraryTableCellView.xib \
 	gui/macosx/UI/VLCPlaylistTableCellView.xib \
 	gui/macosx/UI/VLCLibraryCollectionViewItem.xib \
+	gui/macosx/UI/VLCLibraryCollectionViewAlbumSupplementaryDetailView.xib \
 	gui/macosx/UI/VLCMediaSourceCollectionViewItem.xib \
 	gui/macosx/UI/VLCMediaSourceDeviceCollectionViewItem.xib \
 	gui/macosx/UI/VLCInformationWindow.xib \


=====================================
modules/gui/macosx/UI/VLCLibraryCollectionViewAlbumSupplementaryDetailView.xib
=====================================
@@ -0,0 +1,164 @@
+<?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="System colors introduced in macOS 10.14" minToolsVersion="10.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <customObject id="-2" userLabel="File's Owner" customClass="VLCLibraryCollectionViewAlbumItem"/>
+        <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
+        <customObject id="-3" userLabel="Application" customClass="NSObject"/>
+        <view id="HAc-or-XD8" customClass="VLCLibraryCollectionViewAlbumSupplementaryDetailView">
+            <rect key="frame" x="0.0" y="0.0" width="1061" height="332"/>
+            <autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
+            <subviews>
+                <box boxType="custom" borderType="none" cornerRadius="4" titlePosition="noTitle" translatesAutoresizingMaskIntoConstraints="NO" id="TDx-ys-0hc">
+                    <rect key="frame" x="0.0" y="0.0" width="1061" height="312"/>
+                    <view key="contentView" id="l4M-qd-E0u">
+                        <rect key="frame" x="0.0" y="0.0" width="1061" height="312"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                    </view>
+                    <color key="borderColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+                    <color key="fillColor" name="separatorColor" catalog="System" colorSpace="catalog"/>
+                </box>
+                <stackView distribution="fill" orientation="horizontal" alignment="top" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="FWp-yd-2Pm">
+                    <rect key="frame" x="0.0" y="0.0" width="1061" height="302"/>
+                    <subviews>
+                        <stackView distribution="fill" orientation="vertical" alignment="leading" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="TOx-1e-6D9">
+                            <rect key="frame" x="0.0" y="10" width="351" height="292"/>
+                            <subviews>
+                                <imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="xZd-Hk-h2M">
+                                    <rect key="frame" x="10" y="0.0" width="331" height="292"/>
+                                    <imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="no-art" id="6X6-Og-u8A"/>
+                                </imageView>
+                            </subviews>
+                            <constraints>
+                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="xZd-Hk-h2M" secondAttribute="trailing" constant="10" id="GHL-NF-uZf"/>
+                                <constraint firstItem="xZd-Hk-h2M" firstAttribute="top" secondItem="TOx-1e-6D9" secondAttribute="top" id="fYG-48-y9a"/>
+                                <constraint firstItem="xZd-Hk-h2M" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="TOx-1e-6D9" secondAttribute="leading" constant="10" id="gvA-cd-m3X"/>
+                                <constraint firstItem="xZd-Hk-h2M" firstAttribute="centerX" secondItem="TOx-1e-6D9" secondAttribute="centerX" id="zLM-Ut-V4H"/>
+                            </constraints>
+                            <visibilityPriorities>
+                                <integer value="1000"/>
+                            </visibilityPriorities>
+                            <customSpacing>
+                                <real value="3.4028234663852886e+38"/>
+                            </customSpacing>
+                        </stackView>
+                        <stackView distribution="fill" orientation="vertical" alignment="leading" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="bw7-QB-Ssc">
+                            <rect key="frame" x="359" y="20" width="702" height="282"/>
+                            <subviews>
+                                <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="nCe-dY-YMM">
+                                    <rect key="frame" x="-2" y="230" width="124" height="52"/>
+                                    <textFieldCell key="cell" lineBreakMode="clipping" title="Album 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>
+                                <textField horizontalHuggingPriority="251" verticalHuggingPriority="751" translatesAutoresizingMaskIntoConstraints="NO" id="HnP-Fk-juB">
+                                    <rect key="frame" x="-2" y="206" width="87" height="16"/>
+                                    <textFieldCell key="cell" lineBreakMode="clipping" title="Album details" id="Nwk-76-Wx9">
+                                        <font key="font" metaFont="system"/>
+                                        <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="52" horizontalPageScroll="10" verticalLineScroll="52" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" horizontalScrollElasticity="none" id="9ZS-oy-iP9">
+                                    <rect key="frame" x="0.0" y="0.0" width="701" height="198"/>
+                                    <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="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" columnReordering="NO" multipleSelection="NO" autosaveColumns="NO" rowHeight="50" viewBased="YES" id="eEJ-WA-0aM">
+                                                <rect key="frame" x="0.0" y="0.0" width="701" height="198"/>
+                                                <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                                                <size key="intercellSpacing" width="3" height="2"/>
+                                                <color key="backgroundColor" red="1" green="1" blue="1" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
+                                                <tableViewGridLines key="gridStyleMask" horizontal="YES"/>
+                                                <color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
+                                                <tableColumns>
+                                                    <tableColumn editable="NO" width="641" minWidth="10" maxWidth="1000" id="tVn-dP-rPg">
+                                                        <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border">
+                                                            <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
+                                                            <color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
+                                                        </tableHeaderCell>
+                                                        <textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Text Cell" id="LqL-cf-UYG">
+                                                            <font key="font" metaFont="system"/>
+                                                            <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+                                                            <color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
+                                                        </textFieldCell>
+                                                        <tableColumnResizingMask key="resizingMask" resizeWithTable="YES"/>
+                                                        <prototypeCellViews>
+                                                            <tableCellView id="vmz-MH-Uum">
+                                                                <rect key="frame" x="11" y="1" width="650" height="24"/>
+                                                                <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                                                            </tableCellView>
+                                                        </prototypeCellViews>
+                                                    </tableColumn>
+                                                </tableColumns>
+                                            </tableView>
+                                        </subviews>
+                                        <nil key="backgroundColor"/>
+                                    </clipView>
+                                    <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"/>
+                                <integer value="1000"/>
+                            </visibilityPriorities>
+                            <customSpacing>
+                                <real value="3.4028234663852886e+38"/>
+                                <real value="3.4028234663852886e+38"/>
+                                <real value="3.4028234663852886e+38"/>
+                            </customSpacing>
+                        </stackView>
+                    </subviews>
+                    <constraints>
+                        <constraint firstAttribute="bottom" secondItem="TOx-1e-6D9" secondAttribute="bottom" constant="10" id="sVI-op-597"/>
+                        <constraint firstItem="TOx-1e-6D9" firstAttribute="width" secondItem="bw7-QB-Ssc" secondAttribute="width" multiplier="0.5" id="wgl-yE-5rb"/>
+                    </constraints>
+                    <visibilityPriorities>
+                        <integer value="1000"/>
+                        <integer value="1000"/>
+                    </visibilityPriorities>
+                    <customSpacing>
+                        <real value="3.4028234663852886e+38"/>
+                        <real value="3.4028234663852886e+38"/>
+                    </customSpacing>
+                </stackView>
+            </subviews>
+            <constraints>
+                <constraint firstItem="TDx-ys-0hc" firstAttribute="trailing" secondItem="FWp-yd-2Pm" secondAttribute="trailing" id="288-Qz-cb7"/>
+                <constraint firstItem="TDx-ys-0hc" firstAttribute="leading" secondItem="FWp-yd-2Pm" secondAttribute="leading" id="4AV-xO-cVg"/>
+                <constraint firstItem="FWp-yd-2Pm" firstAttribute="leading" secondItem="HAc-or-XD8" secondAttribute="leading" id="D62-3E-aDO"/>
+                <constraint firstItem="TDx-ys-0hc" firstAttribute="top" secondItem="HAc-or-XD8" secondAttribute="top" constant="20" id="Wob-l9-MuU"/>
+                <constraint firstAttribute="bottom" secondItem="TDx-ys-0hc" secondAttribute="bottom" id="aub-cX-QrF"/>
+                <constraint firstAttribute="trailing" secondItem="FWp-yd-2Pm" secondAttribute="trailing" id="cPm-6m-umY"/>
+                <constraint firstItem="FWp-yd-2Pm" firstAttribute="top" secondItem="TDx-ys-0hc" secondAttribute="top" constant="10" id="cVs-ac-sSk"/>
+                <constraint firstItem="FWp-yd-2Pm" firstAttribute="bottom" secondItem="TDx-ys-0hc" secondAttribute="bottom" id="pZF-BE-cG1"/>
+            </constraints>
+            <connections>
+                <outlet property="albumArtworkImageView" destination="xZd-Hk-h2M" id="J8l-V9-P06"/>
+                <outlet property="albumDetailsTextField" destination="HnP-Fk-juB" id="Hm3-l8-a9s"/>
+                <outlet property="albumTitleTextField" destination="nCe-dY-YMM" id="h3l-p0-w3e"/>
+                <outlet property="albumTracksTableView" destination="eEJ-WA-0aM" id="l8k-M9-a8e"/>
+            </connections>
+            <point key="canvasLocation" x="-237.5" y="-257"/>
+        </view>
+    </objects>
+    <resources>
+        <image name="no-art" width="128" height="128"/>
+    </resources>
+</document>


=====================================
modules/gui/macosx/library/VLCLibraryAlbumTableCellView.h
=====================================
@@ -25,12 +25,13 @@
 NS_ASSUME_NONNULL_BEGIN
 
 @class VLCImageView;
- at class VLCLibraryTracksDataSource;
 @class VLCTrackingView;
 @class VLCMediaLibraryAlbum;
 
 @interface VLCLibraryAlbumTableCellView : NSTableCellView
 
+extern NSString *VLCAudioLibraryCellIdentifier;
+
 + (CGFloat)defaultHeight;
 + (CGFloat)heightForAlbum:(VLCMediaLibraryAlbum *)album;
 


=====================================
modules/gui/macosx/library/VLCLibraryAlbumTableCellView.m
=====================================
@@ -29,22 +29,17 @@
 #import "library/VLCLibraryController.h"
 #import "library/VLCLibraryDataTypes.h"
 #import "library/VLCLibraryTableCellView.h"
+#import "library/VLCLibraryAlbumTracksDataSource.h"
 
 NSString *VLCAudioLibraryCellIdentifier = @"VLCAudioLibraryCellIdentifier";
 const CGFloat VLCLibraryTracksRowHeight = 50.;
 const CGFloat VLCLibraryAlbumTableCellViewDefaultHeight = 168.;
 const CGFloat LayoutSpacer;
 
- at interface VLCLibraryTracksDataSource : NSObject <NSTableViewDataSource, NSTableViewDelegate>
-
- at property (readwrite, retain, nonatomic, nullable) VLCMediaLibraryAlbum *representedAlbum;
-
- at end
-
 @interface VLCLibraryAlbumTableCellView ()
 {
     VLCLibraryController *_libraryController;
-    VLCLibraryTracksDataSource *_tracksDataSource;
+    VLCLibraryAlbumTracksDataSource *_tracksDataSource;
     NSTableView *_tracksTableView;
 }
 @end
@@ -75,7 +70,7 @@ const CGFloat LayoutSpacer;
     _tracksTableView.rowHeight = VLCLibraryTracksRowHeight;
     [_tracksTableView addTableColumn:column];
     _tracksTableView.translatesAutoresizingMaskIntoConstraints = NO;
-    _tracksDataSource = [[VLCLibraryTracksDataSource alloc] init];
+    _tracksDataSource = [[VLCLibraryAlbumTracksDataSource alloc] init];
     _tracksTableView.dataSource = _tracksDataSource;
     _tracksTableView.delegate = _tracksDataSource;
     _tracksTableView.doubleAction = @selector(tracksTableViewDoubleClickAction:);
@@ -152,68 +147,3 @@ const CGFloat LayoutSpacer;
 }
 
 @end
-
- at interface VLCLibraryTracksDataSource ()
-{
-    NSArray *_tracks;
-}
- at end
-
- at implementation VLCLibraryTracksDataSource
-
-- (void)setRepresentedAlbum:(VLCMediaLibraryAlbum *)representedAlbum
-{
-    _representedAlbum = representedAlbum;
-    _tracks = [_representedAlbum tracksAsMediaItems];
-}
-
-- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
-{
-    if (_representedAlbum != nil) {
-        return _representedAlbum.numberOfTracks;
-    }
-
-    return 0;
-}
-
-- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
-{
-    VLCLibraryTableCellView *cellView = [tableView makeViewWithIdentifier:VLCAudioLibraryCellIdentifier owner:self];
-
-    if (cellView == nil) {
-        /* the following code saves us an instance of NSViewController which we don't need */
-        NSNib *nib = [[NSNib alloc] initWithNibNamed:@"VLCLibraryTableCellView" bundle:nil];
-        NSArray *topLevelObjects;
-        if (![nib instantiateWithOwner:self topLevelObjects:&topLevelObjects]) {
-            NSAssert(1, @"Failed to load nib file to show audio library items");
-            return nil;
-        }
-
-        for (id topLevelObject in topLevelObjects) {
-            if ([topLevelObject isKindOfClass:[VLCLibraryTableCellView class]]) {
-                cellView = topLevelObject;
-                break;
-            }
-        }
-        cellView.identifier = VLCAudioLibraryCellIdentifier;
-    }
-
-    VLCMediaLibraryMediaItem *mediaItem = _tracks[row];
-
-    NSImage *image = mediaItem.smallArtworkImage;
-    if (!image) {
-        image = [NSImage imageNamed: @"noart.png"];
-    }
-    cellView.representedImageView.image = image;
-    cellView.representedMediaItem = mediaItem;
-
-    NSString *title = mediaItem.title;
-    cellView.primaryTitleTextField.hidden = NO;
-    cellView.secondaryTitleTextField.hidden = NO;
-    cellView.primaryTitleTextField.stringValue = title;
-    cellView.secondaryTitleTextField.stringValue = [NSString stringWithTime:mediaItem.duration / 1000];
-
-    return cellView;
-}
-
- at end


=====================================
modules/gui/macosx/library/VLCLibraryAlbumTracksDataSource.h
=====================================
@@ -0,0 +1,35 @@
+/*****************************************************************************
+ * VLCLibraryAlbumTracksDataSource.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>
+
+NS_ASSUME_NONNULL_BEGIN
+
+ at class VLCMediaLibraryAlbum;
+
+ at interface VLCLibraryAlbumTracksDataSource : NSObject <NSTableViewDataSource, NSTableViewDelegate>
+
+ at property (readwrite, retain, nonatomic, nullable) VLCMediaLibraryAlbum *representedAlbum;
+
+ at end
+
+NS_ASSUME_NONNULL_END
\ No newline at end of file


=====================================
modules/gui/macosx/library/VLCLibraryAlbumTracksDataSource.m
=====================================
@@ -0,0 +1,98 @@
+/*****************************************************************************
+ * VLCLibraryAlbumTracksDataSource.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 "VLCLibraryAlbumTracksDataSource.h"
+#import "VLCLibraryAlbumTableCellView.h"
+#import "extensions/NSFont+VLCAdditions.h"
+#import "extensions/NSString+Helpers.h"
+#import "views/VLCImageView.h"
+#import "views/VLCTrackingView.h"
+#import "main/VLCMain.h"
+#import "library/VLCLibraryController.h"
+#import "library/VLCLibraryDataTypes.h"
+#import "library/VLCLibraryTableCellView.h"
+#import "library/VLCLibraryAlbumTracksDataSource.h"
+
+ at interface VLCLibraryAlbumTracksDataSource ()
+{
+    NSArray *_tracks;
+}
+ at end
+
+ at implementation VLCLibraryAlbumTracksDataSource
+
+- (void)setRepresentedAlbum:(VLCMediaLibraryAlbum *)representedAlbum
+{
+    _representedAlbum = representedAlbum;
+    _tracks = [_representedAlbum tracksAsMediaItems];
+}
+
+- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
+{
+    if (_representedAlbum != nil) {
+        return _representedAlbum.numberOfTracks;
+    }
+
+    return 0;
+}
+
+- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
+{
+    VLCLibraryTableCellView *cellView = [tableView makeViewWithIdentifier:VLCAudioLibraryCellIdentifier owner:self];
+
+    if (cellView == nil) {
+        /* the following code saves us an instance of NSViewController which we don't need */
+        NSNib *nib = [[NSNib alloc] initWithNibNamed:@"VLCLibraryTableCellView" bundle:nil];
+        NSArray *topLevelObjects;
+        if (![nib instantiateWithOwner:self topLevelObjects:&topLevelObjects]) {
+            NSAssert(1, @"Failed to load nib file to show audio library items");
+            return nil;
+        }
+
+        for (id topLevelObject in topLevelObjects) {
+            if ([topLevelObject isKindOfClass:[VLCLibraryTableCellView class]]) {
+                cellView = topLevelObject;
+                break;
+            }
+        }
+        cellView.identifier = VLCAudioLibraryCellIdentifier;
+    }
+
+    VLCMediaLibraryMediaItem *mediaItem = _tracks[row];
+
+    NSImage *image = mediaItem.smallArtworkImage;
+    if (!image) {
+        image = [NSImage imageNamed: @"noart.png"];
+    }
+    cellView.representedImageView.image = image;
+    cellView.representedMediaItem = mediaItem;
+
+    NSString *title = mediaItem.title;
+    cellView.primaryTitleTextField.hidden = NO;
+    cellView.secondaryTitleTextField.hidden = NO;
+    cellView.primaryTitleTextField.stringValue = title;
+    cellView.secondaryTitleTextField.stringValue = [NSString stringWithTime:mediaItem.duration / 1000];
+
+    return cellView;
+}
+
+ at end
\ No newline at end of file


=====================================
modules/gui/macosx/library/VLCLibraryAudioDataSource.m
=====================================
@@ -30,14 +30,15 @@
 #import "library/VLCLibraryTableCellView.h"
 #import "library/VLCLibraryAlbumTableCellView.h"
 #import "library/VLCLibraryCollectionViewItem.h"
+#import "library/VLCLibraryCollectionViewFlowLayout.h"
+#import "library/VLCLibraryCollectionViewAlbumSupplementaryDetailView.h"
 
 #import "extensions/NSString+Helpers.h"
 #import "views/VLCImageView.h"
 
-static NSString *VLCAudioLibraryCellIdentifier = @"VLCAudioLibraryCellIdentifier";
-
 @interface VLCLibraryAudioDataSource () <NSCollectionViewDelegate, NSCollectionViewDataSource>
 {
+    VLCLibraryCollectionViewFlowLayout *_collectionViewFlowLayout;
     NSInteger _currentSelectedSegment;
     NSArray<NSString *> *_placeholderImageNames;
     NSArray<NSString *> *_placeholderLabelStrings;
@@ -67,12 +68,19 @@ static NSString *VLCAudioLibraryCellIdentifier = @"VLCAudioLibraryCellIdentifier
     _collectionView.delegate = self;
 
     [_collectionView registerClass:[VLCLibraryCollectionViewItem class] forItemWithIdentifier:VLCLibraryCellIdentifier];
-    
-    NSCollectionViewFlowLayout *flowLayout = _collectionView.collectionViewLayout;
-    flowLayout.itemSize = CGSizeMake(214., 260.);
-    flowLayout.sectionInset = NSEdgeInsetsMake(20., 20., 20., 20.);
-    flowLayout.minimumLineSpacing = 20.;
-    flowLayout.minimumInteritemSpacing = 20.;
+
+    NSNib *albumSupplementaryDetailView = [[NSNib alloc] initWithNibNamed:@"VLCLibraryCollectionViewAlbumSupplementaryDetailView" bundle:nil];
+    [_collectionView registerNib:albumSupplementaryDetailView
+      forSupplementaryViewOfKind:VLCLibraryCollectionViewAlbumSupplementaryDetailViewKind 
+                  withIdentifier:VLCLibraryCollectionViewAlbumSupplementaryDetailViewIdentifier];
+
+    _collectionViewFlowLayout = [[VLCLibraryCollectionViewFlowLayout alloc] init];
+    _collectionView.collectionViewLayout = _collectionViewFlowLayout;
+
+    _collectionViewFlowLayout.itemSize = CGSizeMake(214., 260.);
+    _collectionViewFlowLayout.sectionInset = NSEdgeInsetsMake(20., 20., 20., 20.);
+    _collectionViewFlowLayout.minimumLineSpacing = 20.;
+    _collectionViewFlowLayout.minimumInteritemSpacing = 20.;
 
     _groupSelectionTableView.target = self;
     _groupSelectionTableView.doubleAction = @selector(groubSelectionDoubleClickAction:);
@@ -112,6 +120,7 @@ static NSString *VLCAudioLibraryCellIdentifier = @"VLCAudioLibraryCellIdentifier
 
 - (IBAction)segmentedControlAction:(id)sender
 {
+    [_collectionViewFlowLayout resetLayout];
     _currentSelectedSegment = _segmentedControl.selectedSegment;
     switch (_currentSelectedSegment) {
         case 0:
@@ -400,6 +409,42 @@ static NSString *VLCAudioLibraryCellIdentifier = @"VLCAudioLibraryCellIdentifier
     return viewItem;
 }
 
+- (void)collectionView:(NSCollectionView *)collectionView didSelectItemsAtIndexPaths:(NSSet<NSIndexPath *> *)indexPaths
+{
+    NSIndexPath *indexPath = indexPaths.anyObject;
+    if (!indexPath || _currentParentType != VLC_ML_PARENT_ALBUM) {
+        return;
+    }
+
+    [_collectionViewFlowLayout expandDetailSectionAtIndex:indexPath];
+}
+
+- (void)collectionView:(NSCollectionView *)collectionView didDeselectItemsAtIndexPaths:(NSSet<NSIndexPath *> *)indexPaths
+{
+    NSIndexPath *indexPath = indexPaths.anyObject;
+    if (!indexPath || _currentParentType != VLC_ML_PARENT_ALBUM) {
+        return;
+    }
+
+    [_collectionViewFlowLayout collapseDetailSectionAtIndex:indexPath];
+}
+
+- (NSView *)collectionView:(NSCollectionView *)collectionView
+viewForSupplementaryElementOfKind:(NSCollectionViewSupplementaryElementKind)kind
+               atIndexPath:(NSIndexPath *)indexPath
+{
+    if ([kind isEqualToString:VLCLibraryCollectionViewAlbumSupplementaryDetailViewKind] && _currentParentType == VLC_ML_PARENT_ALBUM) {
+        VLCLibraryCollectionViewAlbumSupplementaryDetailView* albumSupplementaryDetailView = [collectionView makeSupplementaryViewOfKind:kind withIdentifier:VLCLibraryCollectionViewAlbumSupplementaryDetailViewKind forIndexPath:indexPath];
+
+        VLCMediaLibraryAlbum *album = _displayedCollection[indexPath.item];
+        albumSupplementaryDetailView.representedAlbum = album;
+
+        return albumSupplementaryDetailView;
+    }
+
+    return nil;
+}
+
 @end
 
 @implementation VLCLibraryGroupDataSource


=====================================
modules/gui/macosx/library/VLCLibraryCollectionViewAlbumSupplementaryDetailView.h
=====================================
@@ -0,0 +1,41 @@
+/*****************************************************************************
+ * VLCLibraryCollectionViewSupplementaryDetailView.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>
+
+NS_ASSUME_NONNULL_BEGIN
+
+ at class VLCMediaLibraryAlbum;
+
+extern NSString *const VLCLibraryCollectionViewAlbumSupplementaryDetailViewIdentifier;
+extern NSCollectionViewSupplementaryElementKind const VLCLibraryCollectionViewAlbumSupplementaryDetailViewKind;
+
+ at interface VLCLibraryCollectionViewAlbumSupplementaryDetailView : NSView <NSCollectionViewElement>
+
+ at property (readwrite, retain, nonatomic) VLCMediaLibraryAlbum *representedAlbum;
+ at property (readwrite, weak) IBOutlet NSTextField *albumTitleTextField;
+ at property (readwrite, weak) IBOutlet NSTextField *albumDetailsTextField;
+ at property (readwrite, weak) IBOutlet NSImageView *albumArtworkImageView;
+ at property (readwrite, weak) IBOutlet NSTableView *albumTracksTableView;
+
+ at end
+
+NS_ASSUME_NONNULL_END
\ No newline at end of file


=====================================
modules/gui/macosx/library/VLCLibraryCollectionViewAlbumSupplementaryDetailView.m
=====================================
@@ -0,0 +1,84 @@
+/*****************************************************************************
+ * VLCLibraryCollectionViewSupplementaryDetailView.m: MacOS X interface module
+ *****************************************************************************
+ * Copyright (C) 2021 VLC authors and VideoLAN
+ *
+ * Authors: Samuel Bassaly <shkshk90 # gmail -dot- com>
+ *          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 "VLCLibraryCollectionViewAlbumSupplementaryDetailView.h"
+
+#import "main/VLCMain.h"
+#import "library/VLCLibraryController.h"
+#import "library/VLCLibraryDataTypes.h"
+#import "library/VLCLibraryModel.h"
+#import "library/VLCLibraryMenuController.h"
+#import "views/VLCImageView.h"
+#import "extensions/NSString+Helpers.h"
+#import "extensions/NSFont+VLCAdditions.h"
+#import "extensions/NSColor+VLCAdditions.h"
+#import "extensions/NSView+VLCAdditions.h"
+#import "library/VLCLibraryAlbumTracksDataSource.h"
+#import "library/VLCLibraryAlbumTableCellView.h"
+
+NSString *const VLCLibraryCollectionViewAlbumSupplementaryDetailViewIdentifier = @"VLCLibraryCollectionViewAlbumSupplementaryDetailViewIdentifier";
+NSCollectionViewSupplementaryElementKind const VLCLibraryCollectionViewAlbumSupplementaryDetailViewKind = @"VLCLibraryCollectionViewAlbumSupplementaryDetailViewIdentifier";
+
+ at interface VLCLibraryCollectionViewAlbumSupplementaryDetailView () 
+{
+    VLCLibraryAlbumTracksDataSource *_tracksDataSource;
+}
+ at end
+
+ at implementation VLCLibraryCollectionViewAlbumSupplementaryDetailView
+
+ at synthesize representedAlbum = _representedAlbum;
+ at synthesize albumTitleTextField = _albumTitleTextField;
+ at synthesize albumDetailsTextField = _albumDetailsTextField;
+ at synthesize albumArtworkImageView = _albumArtworkImageView;
+ at synthesize albumTracksTableView = _albumTracksTableView;
+
+- (void)awakeFromNib
+{
+    _tracksDataSource = [[VLCLibraryAlbumTracksDataSource alloc] init];
+    _albumTracksTableView.dataSource = _tracksDataSource;
+    _albumTracksTableView.delegate = _tracksDataSource;
+}
+
+- (void)setRepresentedAlbum:(VLCMediaLibraryAlbum *)representedAlbum
+{
+    _representedAlbum = representedAlbum;
+    [self updateRepresentation];
+}
+
+- (void)updateRepresentation
+{
+    if (_representedAlbum == nil) {
+        NSAssert(1, @"no media item assigned for collection view item", nil);
+        return;
+    }
+
+    _albumTitleTextField.stringValue = _representedAlbum.displayString;
+    _albumDetailsTextField.stringValue = _representedAlbum.artistName;
+    _albumArtworkImageView.image = _representedAlbum.smallArtworkImage;
+    _tracksDataSource.representedAlbum = _representedAlbum;
+
+    [_albumTracksTableView reloadData];
+}
+
+ at end
\ No newline at end of file


=====================================
modules/gui/macosx/library/VLCLibraryCollectionViewFlowLayout.h
=====================================
@@ -0,0 +1,35 @@
+/*****************************************************************************
+ * VLCLibraryCollectionViewFlowLayout.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>
+
+NS_ASSUME_NONNULL_BEGIN
+
+ at interface VLCLibraryCollectionViewFlowLayout : NSCollectionViewFlowLayout
+
+- (void)expandDetailSectionAtIndex:(NSIndexPath *)indexPath;
+- (void)collapseDetailSectionAtIndex:(NSIndexPath *)indexPath;
+- (void)resetLayout;
+
+ at end
+
+NS_ASSUME_NONNULL_END


=====================================
modules/gui/macosx/library/VLCLibraryCollectionViewFlowLayout.m
=====================================
@@ -0,0 +1,274 @@
+/*****************************************************************************
+ * VLCLibraryCollectionViewFlowLayout.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 "VLCLibraryCollectionViewFlowLayout.h"
+#import "VLCLibraryCollectionViewAlbumSupplementaryDetailView.h"
+
+#pragma mark - Private data
+static const NSUInteger kAnimationSteps = 16;
+static const NSUInteger kWrapAroundValue = (NSUInteger)-1;
+
+static const CGFloat kDetailViewMargin = 8.;
+static const CGFloat kDetailViewCollapsedHeight = 0.;
+static const CGFloat kDetailViewExpandedHeight = 300.;
+
+static const CGFloat kAnimationHeightIncrement = kDetailViewExpandedHeight / (CGFloat)kAnimationSteps;
+
+typedef NS_ENUM(NSUInteger, VLCDetailViewAnimationType)
+{
+    VLCDetailViewAnimationTypeExpand,
+    VLCDetailViewAnimationTypeCollapse,
+};
+
+static CVReturn detailViewAnimationCallback(CVDisplayLinkRef displayLink,
+                                            const CVTimeStamp *inNow,
+                                            const CVTimeStamp *inOutputTime,
+                                            CVOptionFlags flagsIn,
+                                            CVOptionFlags *flagsOut,
+                                            void *displayLinkContext);
+
+#pragma mark - VLCLibraryCollectionViewFlowLayout
+ at interface VLCLibraryCollectionViewFlowLayout ()
+{
+    NSUInteger _lastHeightIndex;
+    CVDisplayLinkRef _displayLinkRef;    
+}
+
+ at property (nonatomic, readwrite) BOOL detailViewIsAnimating;
+ at property (nonatomic, readonly)  BOOL animationIsCollapse;
+ at property (nonatomic, readwrite) NSUInteger animationIndex;
+ at property (nonatomic, readwrite, strong) NSIndexPath *selectedIndexPath;
+
+ at end
+
+ at implementation VLCLibraryCollectionViewFlowLayout
+
+- (instancetype)init
+{
+    self = [super init];
+    if (self == nil) {
+        return nil;
+    }
+    
+    [self resetLayout];
+    
+    return self;
+}
+
+#pragma mark - Public methods
+- (void)expandDetailSectionAtIndex:(NSIndexPath *)indexPath
+{
+    if([_selectedIndexPath isEqual:indexPath]) {
+        return;
+    }
+
+    _selectedIndexPath = indexPath;
+    [self animateDetailViewWithAnimation:VLCDetailViewAnimationTypeExpand];
+}
+
+- (void)collapseDetailSectionAtIndex:(NSIndexPath *)indexPath
+{
+    if(![_selectedIndexPath isEqual:indexPath]) {
+        return;
+    }
+
+    [self animateDetailViewWithAnimation:VLCDetailViewAnimationTypeCollapse];
+}
+
+- (void)resetLayout
+{
+    [self releaseDisplayLink];
+
+    _selectedIndexPath = nil;
+    _detailViewIsAnimating = NO;
+    _animationIndex = 0;
+
+    [self invalidateLayout];
+}
+
+#pragma mark - Flow Layout methods
+
+- (NSCollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
+{
+    NSCollectionViewLayoutAttributes *attributes = [super layoutAttributesForItemAtIndexPath:indexPath];
+
+    if(_selectedIndexPath == nil || indexPath == _selectedIndexPath) {
+        return attributes;
+    }
+
+    [attributes setFrame:[self frameForDisplacedAttributes:attributes]];
+    return attributes;
+}
+
+- (NSArray<__kindof NSCollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(NSRect)rect
+{
+    if (_selectedIndexPath == nil) {
+        return [super layoutAttributesForElementsInRect:rect];
+    }
+
+    NSRect selectedItemFrame = [[self layoutAttributesForItemAtIndexPath:_selectedIndexPath] frame];
+
+    // Computed attributes from parent
+    NSMutableArray<__kindof NSCollectionViewLayoutAttributes *> *layoutAttributesArray = [[super layoutAttributesForElementsInRect:rect] mutableCopy];
+    for (int i = 0; i < layoutAttributesArray.count; i++) {
+        NSCollectionViewLayoutAttributes *attributes = layoutAttributesArray[i];
+        [attributes setFrame:[self frameForDisplacedAttributes:attributes]];
+        layoutAttributesArray[i] = attributes;
+    }
+
+    // Add detail view to the attributes set -- detail view about to be shown
+    [layoutAttributesArray addObject:[self layoutAttributesForSupplementaryViewOfKind:VLCLibraryCollectionViewAlbumSupplementaryDetailViewKind atIndexPath:self.selectedIndexPath]];
+    
+    return layoutAttributesArray;
+}
+
+- (NSCollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSCollectionViewSupplementaryElementKind)elementKind
+                                                                     atIndexPath:(NSIndexPath *)indexPath
+{
+    if ([elementKind isEqualToString:VLCLibraryCollectionViewAlbumSupplementaryDetailViewKind]) {
+        NSCollectionViewLayoutAttributes *detailViewAttributes = [NSCollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:elementKind
+                                                                                                                                withIndexPath:indexPath];
+        NSAssert1(detailViewAttributes != NULL,
+                  @"Failed to create NSCollectionViewLayoutAttributes for view of kind %@.",
+                  VLCLibraryCollectionViewAlbumSupplementaryDetailViewKind );
+        
+        float selectedItemFrameMaxY = _selectedIndexPath == nil ? 0 : NSMaxY([[self layoutAttributesForItemAtIndexPath:_selectedIndexPath] frame]);
+        detailViewAttributes.frame = NSMakeRect(NSMinX(self.collectionView.frame),
+                                                selectedItemFrameMaxY + kDetailViewMargin,
+                                                self.collectionViewContentSize.width - 16.0,
+                                                (_animationIndex * kAnimationHeightIncrement));
+
+        return detailViewAttributes;
+    }
+    
+    NSCollectionViewLayoutAttributes *attributes = [super layoutAttributesForSupplementaryViewOfKind:elementKind
+                                                                                         atIndexPath:indexPath];
+    [attributes setFrame:[self frameForDisplacedAttributes:attributes]];
+    return attributes;
+}
+
+- (NSSet<NSIndexPath *> *)indexPathsToDeleteForSupplementaryViewOfKind:(NSString *)elementKind 
+{
+    if ([elementKind isEqualToString:VLCLibraryCollectionViewAlbumSupplementaryDetailViewKind]) {
+        return [self.collectionView indexPathsForVisibleSupplementaryElementsOfKind:elementKind];
+    }
+    return [NSSet set];
+}
+
+# pragma mark - Calculation of displaced frame attributes
+
+- (NSRect)frameForDisplacedAttributes:(NSCollectionViewLayoutAttributes *)inAttributes {
+    NSRect attributesFrame = inAttributes.frame;
+    if (self.selectedIndexPath) {
+        NSRect selectedItemFrame = [[self layoutAttributesForItemAtIndexPath:_selectedIndexPath] frame];
+        if (NSMinY(attributesFrame) > (NSMaxY(selectedItemFrame))) {
+            attributesFrame.origin.y += (_animationIndex * kAnimationHeightIncrement) + kDetailViewMargin;
+        }
+    }
+    return attributesFrame;
+}
+
+#pragma mark - Detail view animation
+- (void)animateDetailViewWithAnimation:(VLCDetailViewAnimationType)type
+{
+    if (type == VLCDetailViewAnimationTypeExpand) {
+        _animationIsCollapse = NO;
+        _animationIndex = kWrapAroundValue;
+        _lastHeightIndex = kAnimationSteps - 1;
+    } else {
+        _animationIsCollapse = YES;
+        _animationIndex = kAnimationSteps;
+        _lastHeightIndex = 0;
+    }
+    
+    _detailViewIsAnimating = YES;
+    
+    if (_displayLinkRef == NULL) {
+        [self initDisplayLink];
+    }
+}
+
+- (void)initDisplayLink
+{
+    const CVReturn createResult = CVDisplayLinkCreateWithActiveCGDisplays(&_displayLinkRef);
+    
+    if ((createResult != kCVReturnSuccess) || (_displayLinkRef == NULL)) {
+        _detailViewIsAnimating = NO;
+        return;
+    }
+    
+    CVDisplayLinkSetOutputCallback(_displayLinkRef, detailViewAnimationCallback, (__bridge void *)self);
+    CVDisplayLinkStart(_displayLinkRef);
+}
+
+- (void)releaseDisplayLink
+{
+    if (_displayLinkRef == NULL ) {
+        return;
+    }
+    
+    CVDisplayLinkStop(_displayLinkRef);
+    CVDisplayLinkRelease(_displayLinkRef);
+    
+    _displayLinkRef = NULL;
+}
+
+ at end
+
+static CVReturn detailViewAnimationCallback(
+                                            CVDisplayLinkRef displayLink,
+                                            const CVTimeStamp *inNow,
+                                            const CVTimeStamp *inOutputTime,
+                                            CVOptionFlags flagsIn,
+                                            CVOptionFlags *flagsOut,
+                                            void *displayLinkContext)
+{
+    VLCLibraryCollectionViewFlowLayout *bridgedSelf = (__bridge VLCLibraryCollectionViewFlowLayout *)displayLinkContext;
+    BOOL animationFinished = NO;
+    
+    if(bridgedSelf.detailViewIsAnimating) {
+        if (bridgedSelf.animationIsCollapse) {
+            --bridgedSelf.animationIndex;
+            animationFinished = (bridgedSelf.animationIndex == kWrapAroundValue);
+        } else {
+            ++bridgedSelf.animationIndex;
+            animationFinished = (bridgedSelf.animationIndex == kAnimationSteps);
+        }
+    }
+    
+    if (bridgedSelf.detailViewIsAnimating == NO || animationFinished) {
+        bridgedSelf.detailViewIsAnimating = NO;
+        [bridgedSelf releaseDisplayLink];
+        
+        if (bridgedSelf.animationIsCollapse) {
+            bridgedSelf.selectedIndexPath = nil;
+            bridgedSelf.animationIndex = 0;
+        }
+    }
+
+    dispatch_async(dispatch_get_main_queue(), ^(void){
+        [bridgedSelf invalidateLayout];
+    });
+    
+    return kCVReturnSuccess;
+}
+


=====================================
modules/gui/macosx/library/VLCLibraryWindow.m
=====================================
@@ -322,6 +322,9 @@ static void addShadow(NSImageView *__unsafe_unretained imageView)
     _audioGroupSelectionTableView.dataSource = _libraryAudioGroupDataSource;
     _audioGroupSelectionTableView.delegate = _libraryAudioGroupDataSource;
     _audioGroupSelectionTableView.rowHeight = [VLCLibraryAlbumTableCellView defaultHeight];
+    _audioLibraryCollectionView.selectable = YES;
+    _audioLibraryCollectionView.allowsMultipleSelection = NO;
+    _audioLibraryCollectionView.allowsEmptySelection = YES;
 
     _mediaSourceDataSource = [[VLCMediaSourceBaseDataSource alloc] init];
     _mediaSourceDataSource.collectionView = _mediaSourceCollectionView;



View it on GitLab: https://code.videolan.org/videolan/vlc/-/commit/53c0bfa28f720499f1f05936b235ba64a5ef54ea

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/commit/53c0bfa28f720499f1f05936b235ba64a5ef54ea
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